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 true to block)
2064 * @param {Roo.menu.Menu} this
2069 * Fires before this menu is hidden (return true 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 (true === this.fireEvent("beforeshow", this)) {
2296 this.parentMenu = parentMenu;
2301 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2304 * Displays this menu at a specific xy position
2305 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2306 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2308 showAt : function(xy, parentMenu, /* private: */_e){
2309 this.parentMenu = parentMenu;
2314 this.fireEvent("beforeshow", this);
2315 //xy = this.el.adjustForConstraints(xy);
2319 this.hideMenuItems();
2320 this.hidden = false;
2321 this.triggerEl.addClass('open');
2322 this.el.addClass('show');
2324 // reassign x when hitting right
2325 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2326 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2329 // reassign y when hitting bottom
2330 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2331 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2334 // but the list may align on trigger left or trigger top... should it be a properity?
2336 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2341 this.fireEvent("show", this);
2347 this.doFocus.defer(50, this);
2351 doFocus : function(){
2353 this.focusEl.focus();
2358 * Hides this menu and optionally all parent menus
2359 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2361 hide : function(deep)
2363 if (true === this.fireEvent("beforehide", this)) {
2366 this.hideMenuItems();
2367 if(this.el && this.isVisible()){
2369 if(this.activeItem){
2370 this.activeItem.deactivate();
2371 this.activeItem = null;
2373 this.triggerEl.removeClass('open');;
2374 this.el.removeClass('show');
2376 this.fireEvent("hide", this);
2378 if(deep === true && this.parentMenu){
2379 this.parentMenu.hide(true);
2383 onTriggerClick : function(e)
2385 Roo.log('trigger click');
2387 var target = e.getTarget();
2389 Roo.log(target.nodeName.toLowerCase());
2391 if(target.nodeName.toLowerCase() === 'i'){
2397 onTriggerPress : function(e)
2399 Roo.log('trigger press');
2400 //Roo.log(e.getTarget());
2401 // Roo.log(this.triggerEl.dom);
2403 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2404 var pel = Roo.get(e.getTarget());
2405 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2406 Roo.log('is treeview or dropdown?');
2410 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2414 if (this.isVisible()) {
2419 this.show(this.triggerEl, '?', false);
2422 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2429 hideMenuItems : function()
2431 Roo.log("hide Menu Items");
2436 this.el.select('.open',true).each(function(aa) {
2438 aa.removeClass('open');
2442 addxtypeChild : function (tree, cntr) {
2443 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2445 this.menuitems.add(comp);
2457 this.getEl().dom.innerHTML = '';
2458 this.menuitems.clear();
2472 * @class Roo.bootstrap.MenuItem
2473 * @extends Roo.bootstrap.Component
2474 * Bootstrap MenuItem class
2475 * @cfg {String} html the menu label
2476 * @cfg {String} href the link
2477 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2478 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2479 * @cfg {Boolean} active used on sidebars to highlight active itesm
2480 * @cfg {String} fa favicon to show on left of menu item.
2481 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2485 * Create a new MenuItem
2486 * @param {Object} config The config object
2490 Roo.bootstrap.MenuItem = function(config){
2491 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2496 * The raw click event for the entire grid.
2497 * @param {Roo.bootstrap.MenuItem} this
2498 * @param {Roo.EventObject} e
2504 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2508 preventDefault: false,
2509 isContainer : false,
2513 getAutoCreate : function(){
2515 if(this.isContainer){
2518 cls: 'dropdown-menu-item '
2528 cls : 'dropdown-item',
2533 if (this.fa !== false) {
2536 cls : 'fa fa-' + this.fa
2545 cls: 'dropdown-menu-item',
2548 if (this.parent().type == 'treeview') {
2549 cfg.cls = 'treeview-menu';
2552 cfg.cls += ' active';
2557 anc.href = this.href || cfg.cn[0].href ;
2558 ctag.html = this.html || cfg.cn[0].html ;
2562 initEvents: function()
2564 if (this.parent().type == 'treeview') {
2565 this.el.select('a').on('click', this.onClick, this);
2569 this.menu.parentType = this.xtype;
2570 this.menu.triggerEl = this.el;
2571 this.menu = this.addxtype(Roo.apply({}, this.menu));
2575 onClick : function(e)
2577 Roo.log('item on click ');
2579 if(this.preventDefault){
2582 //this.parent().hideMenuItems();
2584 this.fireEvent('click', this, e);
2603 * @class Roo.bootstrap.MenuSeparator
2604 * @extends Roo.bootstrap.Component
2605 * Bootstrap MenuSeparator class
2608 * Create a new MenuItem
2609 * @param {Object} config The config object
2613 Roo.bootstrap.MenuSeparator = function(config){
2614 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2617 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2619 getAutoCreate : function(){
2638 * @class Roo.bootstrap.Modal
2639 * @extends Roo.bootstrap.Component
2640 * Bootstrap Modal class
2641 * @cfg {String} title Title of dialog
2642 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2643 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2644 * @cfg {Boolean} specificTitle default false
2645 * @cfg {Array} buttons Array of buttons or standard button set..
2646 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2647 * @cfg {Boolean} animate default true
2648 * @cfg {Boolean} allow_close default true
2649 * @cfg {Boolean} fitwindow default false
2650 * @cfg {String} size (sm|lg) default empty
2651 * @cfg {Number} max_width set the max width of modal
2655 * Create a new Modal Dialog
2656 * @param {Object} config The config object
2659 Roo.bootstrap.Modal = function(config){
2660 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2665 * The raw btnclick event for the button
2666 * @param {Roo.EventObject} e
2671 * Fire when dialog resize
2672 * @param {Roo.bootstrap.Modal} this
2673 * @param {Roo.EventObject} e
2677 this.buttons = this.buttons || [];
2680 this.tmpl = Roo.factory(this.tmpl);
2685 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2687 title : 'test dialog',
2697 specificTitle: false,
2699 buttonPosition: 'right',
2722 onRender : function(ct, position)
2724 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2727 var cfg = Roo.apply({}, this.getAutoCreate());
2730 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2732 //if (!cfg.name.length) {
2736 cfg.cls += ' ' + this.cls;
2739 cfg.style = this.style;
2741 this.el = Roo.get(document.body).createChild(cfg, position);
2743 //var type = this.el.dom.type;
2746 if(this.tabIndex !== undefined){
2747 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2750 this.dialogEl = this.el.select('.modal-dialog',true).first();
2751 this.bodyEl = this.el.select('.modal-body',true).first();
2752 this.closeEl = this.el.select('.modal-header .close', true).first();
2753 this.headerEl = this.el.select('.modal-header',true).first();
2754 this.titleEl = this.el.select('.modal-title',true).first();
2755 this.footerEl = this.el.select('.modal-footer',true).first();
2757 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2759 //this.el.addClass("x-dlg-modal");
2761 if (this.buttons.length) {
2762 Roo.each(this.buttons, function(bb) {
2763 var b = Roo.apply({}, bb);
2764 b.xns = b.xns || Roo.bootstrap;
2765 b.xtype = b.xtype || 'Button';
2766 if (typeof(b.listeners) == 'undefined') {
2767 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2770 var btn = Roo.factory(b);
2772 btn.render(this.getButtonContainer());
2776 // render the children.
2779 if(typeof(this.items) != 'undefined'){
2780 var items = this.items;
2783 for(var i =0;i < items.length;i++) {
2784 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2788 this.items = nitems;
2790 // where are these used - they used to be body/close/footer
2794 //this.el.addClass([this.fieldClass, this.cls]);
2798 getAutoCreate : function()
2802 html : this.html || ''
2807 cls : 'modal-title',
2811 if(this.specificTitle){
2817 if (this.allow_close && Roo.bootstrap.version == 3) {
2827 if (this.allow_close && Roo.bootstrap.version == 4) {
2837 if(this.size.length){
2838 size = 'modal-' + this.size;
2841 var footer = Roo.bootstrap.version == 3 ?
2843 cls : 'modal-footer',
2847 cls: 'btn-' + this.buttonPosition
2852 { // BS4 uses mr-auto on left buttons....
2853 cls : 'modal-footer'
2864 cls: "modal-dialog " + size,
2867 cls : "modal-content",
2870 cls : 'modal-header',
2885 modal.cls += ' fade';
2891 getChildContainer : function() {
2896 getButtonContainer : function() {
2898 return Roo.bootstrap.version == 4 ?
2899 this.el.select('.modal-footer',true).first()
2900 : this.el.select('.modal-footer div',true).first();
2903 initEvents : function()
2905 if (this.allow_close) {
2906 this.closeEl.on('click', this.hide, this);
2908 Roo.EventManager.onWindowResize(this.resize, this, true);
2916 this.maskEl.setSize(
2917 Roo.lib.Dom.getViewWidth(true),
2918 Roo.lib.Dom.getViewHeight(true)
2921 if (this.fitwindow) {
2925 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2926 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
2931 if(this.max_width !== 0) {
2933 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2936 this.setSize(w, this.height);
2940 if(this.max_height) {
2941 this.setSize(w,Math.min(
2943 Roo.lib.Dom.getViewportHeight(true) - 60
2949 if(!this.fit_content) {
2950 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2954 this.setSize(w, Math.min(
2956 this.headerEl.getHeight() +
2957 this.footerEl.getHeight() +
2958 this.getChildHeight(this.bodyEl.dom.childNodes),
2959 Roo.lib.Dom.getViewportHeight(true) - 60)
2965 setSize : function(w,h)
2976 if (!this.rendered) {
2980 //this.el.setStyle('display', 'block');
2981 this.el.removeClass('hideing');
2982 this.el.dom.style.display='block';
2984 Roo.get(document.body).addClass('modal-open');
2986 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2989 this.el.addClass('show');
2990 this.el.addClass('in');
2993 this.el.addClass('show');
2994 this.el.addClass('in');
2997 // not sure how we can show data in here..
2999 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3002 Roo.get(document.body).addClass("x-body-masked");
3004 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3005 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3006 this.maskEl.dom.style.display = 'block';
3007 this.maskEl.addClass('show');
3012 this.fireEvent('show', this);
3014 // set zindex here - otherwise it appears to be ignored...
3015 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3018 this.items.forEach( function(e) {
3019 e.layout ? e.layout() : false;
3027 if(this.fireEvent("beforehide", this) !== false){
3029 this.maskEl.removeClass('show');
3031 this.maskEl.dom.style.display = '';
3032 Roo.get(document.body).removeClass("x-body-masked");
3033 this.el.removeClass('in');
3034 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3036 if(this.animate){ // why
3037 this.el.addClass('hideing');
3038 this.el.removeClass('show');
3040 if (!this.el.hasClass('hideing')) {
3041 return; // it's been shown again...
3044 this.el.dom.style.display='';
3046 Roo.get(document.body).removeClass('modal-open');
3047 this.el.removeClass('hideing');
3051 this.el.removeClass('show');
3052 this.el.dom.style.display='';
3053 Roo.get(document.body).removeClass('modal-open');
3056 this.fireEvent('hide', this);
3059 isVisible : function()
3062 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3066 addButton : function(str, cb)
3070 var b = Roo.apply({}, { html : str } );
3071 b.xns = b.xns || Roo.bootstrap;
3072 b.xtype = b.xtype || 'Button';
3073 if (typeof(b.listeners) == 'undefined') {
3074 b.listeners = { click : cb.createDelegate(this) };
3077 var btn = Roo.factory(b);
3079 btn.render(this.getButtonContainer());
3085 setDefaultButton : function(btn)
3087 //this.el.select('.modal-footer').()
3090 resizeTo: function(w,h)
3092 this.dialogEl.setWidth(w);
3094 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
3096 this.bodyEl.setHeight(h - diff);
3098 this.fireEvent('resize', this);
3101 setContentSize : function(w, h)
3105 onButtonClick: function(btn,e)
3108 this.fireEvent('btnclick', btn.name, e);
3111 * Set the title of the Dialog
3112 * @param {String} str new Title
3114 setTitle: function(str) {
3115 this.titleEl.dom.innerHTML = str;
3118 * Set the body of the Dialog
3119 * @param {String} str new Title
3121 setBody: function(str) {
3122 this.bodyEl.dom.innerHTML = str;
3125 * Set the body of the Dialog using the template
3126 * @param {Obj} data - apply this data to the template and replace the body contents.
3128 applyBody: function(obj)
3131 Roo.log("Error - using apply Body without a template");
3134 this.tmpl.overwrite(this.bodyEl, obj);
3137 getChildHeight : function(child_nodes)
3141 child_nodes.length == 0
3146 var child_height = 0;
3148 for(var i = 0; i < child_nodes.length; i++) {
3151 * for modal with tabs...
3152 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3154 var layout_childs = child_nodes[i].childNodes;
3156 for(var j = 0; j < layout_childs.length; j++) {
3158 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3160 var layout_body_childs = layout_childs[j].childNodes;
3162 for(var k = 0; k < layout_body_childs.length; k++) {
3164 if(layout_body_childs[k].classList.contains('navbar')) {
3165 child_height += layout_body_childs[k].offsetHeight;
3169 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3171 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3173 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3175 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3176 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3191 child_height += child_nodes[i].offsetHeight;
3192 // Roo.log(child_nodes[i].offsetHeight);
3195 return child_height;
3201 Roo.apply(Roo.bootstrap.Modal, {
3203 * Button config that displays a single OK button
3212 * Button config that displays Yes and No buttons
3228 * Button config that displays OK and Cancel buttons
3243 * Button config that displays Yes, No and Cancel buttons
3267 * messagebox - can be used as a replace
3271 * @class Roo.MessageBox
3272 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3276 Roo.Msg.alert('Status', 'Changes saved successfully.');
3278 // Prompt for user data:
3279 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3281 // process text value...
3285 // Show a dialog using config options:
3287 title:'Save Changes?',
3288 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3289 buttons: Roo.Msg.YESNOCANCEL,
3296 Roo.bootstrap.MessageBox = function(){
3297 var dlg, opt, mask, waitTimer;
3298 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3299 var buttons, activeTextEl, bwidth;
3303 var handleButton = function(button){
3305 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3309 var handleHide = function(){
3311 dlg.el.removeClass(opt.cls);
3314 // Roo.TaskMgr.stop(waitTimer);
3315 // waitTimer = null;
3320 var updateButtons = function(b){
3323 buttons["ok"].hide();
3324 buttons["cancel"].hide();
3325 buttons["yes"].hide();
3326 buttons["no"].hide();
3327 dlg.footerEl.hide();
3331 dlg.footerEl.show();
3332 for(var k in buttons){
3333 if(typeof buttons[k] != "function"){
3336 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3337 width += buttons[k].el.getWidth()+15;
3347 var handleEsc = function(d, k, e){
3348 if(opt && opt.closable !== false){
3358 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3359 * @return {Roo.BasicDialog} The BasicDialog element
3361 getDialog : function(){
3363 dlg = new Roo.bootstrap.Modal( {
3366 //constraintoviewport:false,
3368 //collapsible : false,
3373 //buttonAlign:"center",
3374 closeClick : function(){
3375 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3378 handleButton("cancel");
3383 dlg.on("hide", handleHide);
3385 //dlg.addKeyListener(27, handleEsc);
3387 this.buttons = buttons;
3388 var bt = this.buttonText;
3389 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3390 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3391 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3392 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3394 bodyEl = dlg.bodyEl.createChild({
3396 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3397 '<textarea class="roo-mb-textarea"></textarea>' +
3398 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3400 msgEl = bodyEl.dom.firstChild;
3401 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3402 textboxEl.enableDisplayMode();
3403 textboxEl.addKeyListener([10,13], function(){
3404 if(dlg.isVisible() && opt && opt.buttons){
3407 }else if(opt.buttons.yes){
3408 handleButton("yes");
3412 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3413 textareaEl.enableDisplayMode();
3414 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3415 progressEl.enableDisplayMode();
3417 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3418 var pf = progressEl.dom.firstChild;
3420 pp = Roo.get(pf.firstChild);
3421 pp.setHeight(pf.offsetHeight);
3429 * Updates the message box body text
3430 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3431 * the XHTML-compliant non-breaking space character '&#160;')
3432 * @return {Roo.MessageBox} This message box
3434 updateText : function(text)
3436 if(!dlg.isVisible() && !opt.width){
3437 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3438 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3440 msgEl.innerHTML = text || ' ';
3442 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3443 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3445 Math.min(opt.width || cw , this.maxWidth),
3446 Math.max(opt.minWidth || this.minWidth, bwidth)
3449 activeTextEl.setWidth(w);
3451 if(dlg.isVisible()){
3452 dlg.fixedcenter = false;
3454 // to big, make it scroll. = But as usual stupid IE does not support
3457 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3458 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3459 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3461 bodyEl.dom.style.height = '';
3462 bodyEl.dom.style.overflowY = '';
3465 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3467 bodyEl.dom.style.overflowX = '';
3470 dlg.setContentSize(w, bodyEl.getHeight());
3471 if(dlg.isVisible()){
3472 dlg.fixedcenter = true;
3478 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3479 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3480 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3481 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3482 * @return {Roo.MessageBox} This message box
3484 updateProgress : function(value, text){
3486 this.updateText(text);
3489 if (pp) { // weird bug on my firefox - for some reason this is not defined
3490 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3491 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3497 * Returns true if the message box is currently displayed
3498 * @return {Boolean} True if the message box is visible, else false
3500 isVisible : function(){
3501 return dlg && dlg.isVisible();
3505 * Hides the message box if it is displayed
3508 if(this.isVisible()){
3514 * Displays a new message box, or reinitializes an existing message box, based on the config options
3515 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3516 * The following config object properties are supported:
3518 Property Type Description
3519 ---------- --------------- ------------------------------------------------------------------------------------
3520 animEl String/Element An id or Element from which the message box should animate as it opens and
3521 closes (defaults to undefined)
3522 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3523 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3524 closable Boolean False to hide the top-right close button (defaults to true). Note that
3525 progress and wait dialogs will ignore this property and always hide the
3526 close button as they can only be closed programmatically.
3527 cls String A custom CSS class to apply to the message box element
3528 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3529 displayed (defaults to 75)
3530 fn Function A callback function to execute after closing the dialog. The arguments to the
3531 function will be btn (the name of the button that was clicked, if applicable,
3532 e.g. "ok"), and text (the value of the active text field, if applicable).
3533 Progress and wait dialogs will ignore this option since they do not respond to
3534 user actions and can only be closed programmatically, so any required function
3535 should be called by the same code after it closes the dialog.
3536 icon String A CSS class that provides a background image to be used as an icon for
3537 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3538 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3539 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3540 modal Boolean False to allow user interaction with the page while the message box is
3541 displayed (defaults to true)
3542 msg String A string that will replace the existing message box body text (defaults
3543 to the XHTML-compliant non-breaking space character ' ')
3544 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3545 progress Boolean True to display a progress bar (defaults to false)
3546 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3547 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3548 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3549 title String The title text
3550 value String The string value to set into the active textbox element if displayed
3551 wait Boolean True to display a progress bar (defaults to false)
3552 width Number The width of the dialog in pixels
3559 msg: 'Please enter your address:',
3561 buttons: Roo.MessageBox.OKCANCEL,
3564 animEl: 'addAddressBtn'
3567 * @param {Object} config Configuration options
3568 * @return {Roo.MessageBox} This message box
3570 show : function(options)
3573 // this causes nightmares if you show one dialog after another
3574 // especially on callbacks..
3576 if(this.isVisible()){
3579 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3580 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3581 Roo.log("New Dialog Message:" + options.msg )
3582 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3583 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3586 var d = this.getDialog();
3588 d.setTitle(opt.title || " ");
3589 d.closeEl.setDisplayed(opt.closable !== false);
3590 activeTextEl = textboxEl;
3591 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3596 textareaEl.setHeight(typeof opt.multiline == "number" ?
3597 opt.multiline : this.defaultTextHeight);
3598 activeTextEl = textareaEl;
3607 progressEl.setDisplayed(opt.progress === true);
3609 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3611 this.updateProgress(0);
3612 activeTextEl.dom.value = opt.value || "";
3614 dlg.setDefaultButton(activeTextEl);
3616 var bs = opt.buttons;
3620 }else if(bs && bs.yes){
3621 db = buttons["yes"];
3623 dlg.setDefaultButton(db);
3625 bwidth = updateButtons(opt.buttons);
3626 this.updateText(opt.msg);
3628 d.el.addClass(opt.cls);
3630 d.proxyDrag = opt.proxyDrag === true;
3631 d.modal = opt.modal !== false;
3632 d.mask = opt.modal !== false ? mask : false;
3634 // force it to the end of the z-index stack so it gets a cursor in FF
3635 document.body.appendChild(dlg.el.dom);
3636 d.animateTarget = null;
3637 d.show(options.animEl);
3643 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3644 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3645 * and closing the message box when the process is complete.
3646 * @param {String} title The title bar text
3647 * @param {String} msg The message box body text
3648 * @return {Roo.MessageBox} This message box
3650 progress : function(title, msg){
3657 minWidth: this.minProgressWidth,
3664 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3665 * If a callback function is passed it will be called after the user clicks the button, and the
3666 * id of the button that was clicked will be passed as the only parameter to the callback
3667 * (could also be the top-right close button).
3668 * @param {String} title The title bar text
3669 * @param {String} msg The message box body text
3670 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3671 * @param {Object} scope (optional) The scope of the callback function
3672 * @return {Roo.MessageBox} This message box
3674 alert : function(title, msg, fn, scope)
3689 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3690 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3691 * You are responsible for closing the message box when the process is complete.
3692 * @param {String} msg The message box body text
3693 * @param {String} title (optional) The title bar text
3694 * @return {Roo.MessageBox} This message box
3696 wait : function(msg, title){
3707 waitTimer = Roo.TaskMgr.start({
3709 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3717 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3718 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3719 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3720 * @param {String} title The title bar text
3721 * @param {String} msg The message box body text
3722 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3723 * @param {Object} scope (optional) The scope of the callback function
3724 * @return {Roo.MessageBox} This message box
3726 confirm : function(title, msg, fn, scope){
3730 buttons: this.YESNO,
3739 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3740 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3741 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3742 * (could also be the top-right close button) and the text that was entered will be passed as the two
3743 * parameters to the callback.
3744 * @param {String} title The title bar text
3745 * @param {String} msg The message box body text
3746 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3747 * @param {Object} scope (optional) The scope of the callback function
3748 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3749 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3750 * @return {Roo.MessageBox} This message box
3752 prompt : function(title, msg, fn, scope, multiline){
3756 buttons: this.OKCANCEL,
3761 multiline: multiline,
3768 * Button config that displays a single OK button
3773 * Button config that displays Yes and No buttons
3776 YESNO : {yes:true, no:true},
3778 * Button config that displays OK and Cancel buttons
3781 OKCANCEL : {ok:true, cancel:true},
3783 * Button config that displays Yes, No and Cancel buttons
3786 YESNOCANCEL : {yes:true, no:true, cancel:true},
3789 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3792 defaultTextHeight : 75,
3794 * The maximum width in pixels of the message box (defaults to 600)
3799 * The minimum width in pixels of the message box (defaults to 100)
3804 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3805 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3808 minProgressWidth : 250,
3810 * An object containing the default button text strings that can be overriden for localized language support.
3811 * Supported properties are: ok, cancel, yes and no.
3812 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3825 * Shorthand for {@link Roo.MessageBox}
3827 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3828 Roo.Msg = Roo.Msg || Roo.MessageBox;
3837 * @class Roo.bootstrap.Navbar
3838 * @extends Roo.bootstrap.Component
3839 * Bootstrap Navbar class
3842 * Create a new Navbar
3843 * @param {Object} config The config object
3847 Roo.bootstrap.Navbar = function(config){
3848 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3852 * @event beforetoggle
3853 * Fire before toggle the menu
3854 * @param {Roo.EventObject} e
3856 "beforetoggle" : true
3860 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3869 getAutoCreate : function(){
3872 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3876 initEvents :function ()
3878 //Roo.log(this.el.select('.navbar-toggle',true));
3879 this.el.select('.navbar-toggle',true).on('click', function() {
3880 if(this.fireEvent('beforetoggle', this) !== false){
3881 var ce = this.el.select('.navbar-collapse',true).first();
3882 ce.toggleClass('in'); // old...
3883 if (ce.hasClass('collapse')) {
3885 ce.removeClass('collapse');
3886 ce.addClass('show');
3887 var h = ce.getHeight();
3889 ce.removeClass('show');
3890 // at this point we should be able to see it..
3891 ce.addClass('collapsing');
3893 ce.setHeight(0); // resize it ...
3894 ce.on('transitionend', function() {
3895 Roo.log('done transition');
3896 ce.removeClass('collapsing');
3897 ce.addClass('show');
3898 ce.removeClass('collapse');
3900 ce.dom.style.height = '';
3901 }, this, { single: true} );
3905 ce.setHeight(ce.getHeight());
3906 ce.removeClass('show');
3907 ce.addClass('collapsing');
3909 ce.on('transitionend', function() {
3910 ce.dom.style.height = '';
3911 ce.removeClass('collapsing');
3912 ce.addClass('collapse');
3913 }, this, { single: true} );
3925 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3927 var size = this.el.getSize();
3928 this.maskEl.setSize(size.width, size.height);
3929 this.maskEl.enableDisplayMode("block");
3938 getChildContainer : function()
3940 if (this.el && this.el.select('.collapse').getCount()) {
3941 return this.el.select('.collapse',true).first();
3974 * @class Roo.bootstrap.NavSimplebar
3975 * @extends Roo.bootstrap.Navbar
3976 * Bootstrap Sidebar class
3978 * @cfg {Boolean} inverse is inverted color
3980 * @cfg {String} type (nav | pills | tabs)
3981 * @cfg {Boolean} arrangement stacked | justified
3982 * @cfg {String} align (left | right) alignment
3984 * @cfg {Boolean} main (true|false) main nav bar? default false
3985 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3987 * @cfg {String} tag (header|footer|nav|div) default is nav
3989 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
3993 * Create a new Sidebar
3994 * @param {Object} config The config object
3998 Roo.bootstrap.NavSimplebar = function(config){
3999 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4002 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4018 getAutoCreate : function(){
4022 tag : this.tag || 'div',
4023 cls : 'navbar navbar-expand-lg roo-navbar-simple'
4025 if (['light','white'].indexOf(this.weight) > -1) {
4026 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4028 cfg.cls += ' bg-' + this.weight;
4031 cfg.cls += ' navbar-inverse';
4035 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4037 //if (Roo.bootstrap.version == 4) {
4049 this.type = this.type || 'nav';
4050 if (['tabs','pills'].indexOf(this.type) != -1) {
4051 cfg.cn[0].cls += ' nav-' + this.type
4055 if (this.type!=='nav') {
4056 Roo.log('nav type must be nav/tabs/pills')
4058 cfg.cn[0].cls += ' navbar-nav'
4064 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4065 cfg.cn[0].cls += ' nav-' + this.arrangement;
4069 if (this.align === 'right') {
4070 cfg.cn[0].cls += ' navbar-right';
4095 * navbar-expand-md fixed-top
4099 * @class Roo.bootstrap.NavHeaderbar
4100 * @extends Roo.bootstrap.NavSimplebar
4101 * Bootstrap Sidebar class
4103 * @cfg {String} brand what is brand
4104 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4105 * @cfg {String} brand_href href of the brand
4106 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4107 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4108 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4109 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4112 * Create a new Sidebar
4113 * @param {Object} config The config object
4117 Roo.bootstrap.NavHeaderbar = function(config){
4118 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4122 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4129 desktopCenter : false,
4132 getAutoCreate : function(){
4135 tag: this.nav || 'nav',
4136 cls: 'navbar navbar-expand-md',
4142 if (this.desktopCenter) {
4143 cn.push({cls : 'container', cn : []});
4151 cls: 'navbar-toggle navbar-toggler',
4152 'data-toggle': 'collapse',
4157 html: 'Toggle navigation'
4161 cls: 'icon-bar navbar-toggler-icon'
4174 cn.push( Roo.bootstrap.version == 4 ? btn : {
4176 cls: 'navbar-header',
4185 cls: 'collapse navbar-collapse',
4189 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4191 if (['light','white'].indexOf(this.weight) > -1) {
4192 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4194 cfg.cls += ' bg-' + this.weight;
4197 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4198 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4200 // tag can override this..
4202 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4205 if (this.brand !== '') {
4206 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4207 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4209 href: this.brand_href ? this.brand_href : '#',
4210 cls: 'navbar-brand',
4218 cfg.cls += ' main-nav';
4226 getHeaderChildContainer : function()
4228 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4229 return this.el.select('.navbar-header',true).first();
4232 return this.getChildContainer();
4236 initEvents : function()
4238 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4240 if (this.autohide) {
4245 Roo.get(document).on('scroll',function(e) {
4246 var ns = Roo.get(document).getScroll().top;
4247 var os = prevScroll;
4251 ft.removeClass('slideDown');
4252 ft.addClass('slideUp');
4255 ft.removeClass('slideUp');
4256 ft.addClass('slideDown');
4277 * @class Roo.bootstrap.NavSidebar
4278 * @extends Roo.bootstrap.Navbar
4279 * Bootstrap Sidebar class
4282 * Create a new Sidebar
4283 * @param {Object} config The config object
4287 Roo.bootstrap.NavSidebar = function(config){
4288 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4291 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4293 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4295 getAutoCreate : function(){
4300 cls: 'sidebar sidebar-nav'
4322 * @class Roo.bootstrap.NavGroup
4323 * @extends Roo.bootstrap.Component
4324 * Bootstrap NavGroup class
4325 * @cfg {String} align (left|right)
4326 * @cfg {Boolean} inverse
4327 * @cfg {String} type (nav|pills|tab) default nav
4328 * @cfg {String} navId - reference Id for navbar.
4332 * Create a new nav group
4333 * @param {Object} config The config object
4336 Roo.bootstrap.NavGroup = function(config){
4337 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4340 Roo.bootstrap.NavGroup.register(this);
4344 * Fires when the active item changes
4345 * @param {Roo.bootstrap.NavGroup} this
4346 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4347 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4354 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4365 getAutoCreate : function()
4367 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4373 if (Roo.bootstrap.version == 4) {
4374 if (['tabs','pills'].indexOf(this.type) != -1) {
4375 cfg.cls += ' nav-' + this.type;
4377 cfg.cls += ' navbar-nav';
4380 if (['tabs','pills'].indexOf(this.type) != -1) {
4381 cfg.cls += ' nav-' + this.type
4383 if (this.type !== 'nav') {
4384 Roo.log('nav type must be nav/tabs/pills')
4386 cfg.cls += ' navbar-nav'
4390 if (this.parent() && this.parent().sidebar) {
4393 cls: 'dashboard-menu sidebar-menu'
4399 if (this.form === true) {
4402 cls: 'navbar-form form-inline'
4405 if (this.align === 'right') {
4406 cfg.cls += ' navbar-right ml-md-auto';
4408 cfg.cls += ' navbar-left';
4412 if (this.align === 'right') {
4413 cfg.cls += ' navbar-right ml-md-auto';
4415 cfg.cls += ' mr-auto';
4419 cfg.cls += ' navbar-inverse';
4427 * sets the active Navigation item
4428 * @param {Roo.bootstrap.NavItem} the new current navitem
4430 setActiveItem : function(item)
4433 Roo.each(this.navItems, function(v){
4438 v.setActive(false, true);
4445 item.setActive(true, true);
4446 this.fireEvent('changed', this, item, prev);
4451 * gets the active Navigation item
4452 * @return {Roo.bootstrap.NavItem} the current navitem
4454 getActive : function()
4458 Roo.each(this.navItems, function(v){
4469 indexOfNav : function()
4473 Roo.each(this.navItems, function(v,i){
4484 * adds a Navigation item
4485 * @param {Roo.bootstrap.NavItem} the navitem to add
4487 addItem : function(cfg)
4489 if (this.form && Roo.bootstrap.version == 4) {
4492 var cn = new Roo.bootstrap.NavItem(cfg);
4494 cn.parentId = this.id;
4495 cn.onRender(this.el, null);
4499 * register a Navigation item
4500 * @param {Roo.bootstrap.NavItem} the navitem to add
4502 register : function(item)
4504 this.navItems.push( item);
4505 item.navId = this.navId;
4510 * clear all the Navigation item
4513 clearAll : function()
4516 this.el.dom.innerHTML = '';
4519 getNavItem: function(tabId)
4522 Roo.each(this.navItems, function(e) {
4523 if (e.tabId == tabId) {
4533 setActiveNext : function()
4535 var i = this.indexOfNav(this.getActive());
4536 if (i > this.navItems.length) {
4539 this.setActiveItem(this.navItems[i+1]);
4541 setActivePrev : function()
4543 var i = this.indexOfNav(this.getActive());
4547 this.setActiveItem(this.navItems[i-1]);
4549 clearWasActive : function(except) {
4550 Roo.each(this.navItems, function(e) {
4551 if (e.tabId != except.tabId && e.was_active) {
4552 e.was_active = false;
4559 getWasActive : function ()
4562 Roo.each(this.navItems, function(e) {
4577 Roo.apply(Roo.bootstrap.NavGroup, {
4581 * register a Navigation Group
4582 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4584 register : function(navgrp)
4586 this.groups[navgrp.navId] = navgrp;
4590 * fetch a Navigation Group based on the navigation ID
4591 * @param {string} the navgroup to add
4592 * @returns {Roo.bootstrap.NavGroup} the navgroup
4594 get: function(navId) {
4595 if (typeof(this.groups[navId]) == 'undefined') {
4597 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4599 return this.groups[navId] ;
4614 * @class Roo.bootstrap.NavItem
4615 * @extends Roo.bootstrap.Component
4616 * Bootstrap Navbar.NavItem class
4617 * @cfg {String} href link to
4618 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4620 * @cfg {String} html content of button
4621 * @cfg {String} badge text inside badge
4622 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4623 * @cfg {String} glyphicon DEPRICATED - use fa
4624 * @cfg {String} icon DEPRICATED - use fa
4625 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4626 * @cfg {Boolean} active Is item active
4627 * @cfg {Boolean} disabled Is item disabled
4629 * @cfg {Boolean} preventDefault (true | false) default false
4630 * @cfg {String} tabId the tab that this item activates.
4631 * @cfg {String} tagtype (a|span) render as a href or span?
4632 * @cfg {Boolean} animateRef (true|false) link to element default false
4635 * Create a new Navbar Item
4636 * @param {Object} config The config object
4638 Roo.bootstrap.NavItem = function(config){
4639 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4644 * The raw click event for the entire grid.
4645 * @param {Roo.EventObject} e
4650 * Fires when the active item active state changes
4651 * @param {Roo.bootstrap.NavItem} this
4652 * @param {boolean} state the new state
4658 * Fires when scroll to element
4659 * @param {Roo.bootstrap.NavItem} this
4660 * @param {Object} options
4661 * @param {Roo.EventObject} e
4669 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4678 preventDefault : false,
4686 button_outline : false,
4690 getAutoCreate : function(){
4698 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4700 if (this.disabled) {
4701 cfg.cls += ' disabled';
4705 if (this.button_weight.length) {
4706 cfg.tag = this.href ? 'a' : 'button';
4707 cfg.html = this.html || '';
4708 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4710 cfg.href = this.href;
4713 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4716 // menu .. should add dropdown-menu class - so no need for carat..
4718 if (this.badge !== '') {
4720 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4725 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4729 href : this.href || "#",
4730 html: this.html || ''
4733 if (this.tagtype == 'a') {
4734 cfg.cn[0].cls = 'nav-link';
4737 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4740 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4742 if(this.glyphicon) {
4743 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4748 cfg.cn[0].html += " <span class='caret'></span>";
4752 if (this.badge !== '') {
4754 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4762 onRender : function(ct, position)
4764 // Roo.log("Call onRender: " + this.xtype);
4765 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4769 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4770 this.navLink = this.el.select('.nav-link',true).first();
4775 initEvents: function()
4777 if (typeof (this.menu) != 'undefined') {
4778 this.menu.parentType = this.xtype;
4779 this.menu.triggerEl = this.el;
4780 this.menu = this.addxtype(Roo.apply({}, this.menu));
4783 this.el.select('a',true).on('click', this.onClick, this);
4785 if(this.tagtype == 'span'){
4786 this.el.select('span',true).on('click', this.onClick, this);
4789 // at this point parent should be available..
4790 this.parent().register(this);
4793 onClick : function(e)
4795 if (e.getTarget('.dropdown-menu-item')) {
4796 // did you click on a menu itemm.... - then don't trigger onclick..
4801 this.preventDefault ||
4804 Roo.log("NavItem - prevent Default?");
4808 if (this.disabled) {
4812 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4813 if (tg && tg.transition) {
4814 Roo.log("waiting for the transitionend");
4820 //Roo.log("fire event clicked");
4821 if(this.fireEvent('click', this, e) === false){
4825 if(this.tagtype == 'span'){
4829 //Roo.log(this.href);
4830 var ael = this.el.select('a',true).first();
4833 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4834 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4835 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4836 return; // ignore... - it's a 'hash' to another page.
4838 Roo.log("NavItem - prevent Default?");
4840 this.scrollToElement(e);
4844 var p = this.parent();
4846 if (['tabs','pills'].indexOf(p.type)!==-1) {
4847 if (typeof(p.setActiveItem) !== 'undefined') {
4848 p.setActiveItem(this);
4852 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4853 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4854 // remove the collapsed menu expand...
4855 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4859 isActive: function () {
4862 setActive : function(state, fire, is_was_active)
4864 if (this.active && !state && this.navId) {
4865 this.was_active = true;
4866 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4868 nv.clearWasActive(this);
4872 this.active = state;
4875 this.el.removeClass('active');
4876 this.navLink ? this.navLink.removeClass('active') : false;
4877 } else if (!this.el.hasClass('active')) {
4879 this.el.addClass('active');
4880 if (Roo.bootstrap.version == 4 && this.navLink ) {
4881 this.navLink.addClass('active');
4886 this.fireEvent('changed', this, state);
4889 // show a panel if it's registered and related..
4891 if (!this.navId || !this.tabId || !state || is_was_active) {
4895 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4899 var pan = tg.getPanelByName(this.tabId);
4903 // if we can not flip to new panel - go back to old nav highlight..
4904 if (false == tg.showPanel(pan)) {
4905 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4907 var onav = nv.getWasActive();
4909 onav.setActive(true, false, true);
4918 // this should not be here...
4919 setDisabled : function(state)
4921 this.disabled = state;
4923 this.el.removeClass('disabled');
4924 } else if (!this.el.hasClass('disabled')) {
4925 this.el.addClass('disabled');
4931 * Fetch the element to display the tooltip on.
4932 * @return {Roo.Element} defaults to this.el
4934 tooltipEl : function()
4936 return this.el.select('' + this.tagtype + '', true).first();
4939 scrollToElement : function(e)
4941 var c = document.body;
4944 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4946 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4947 c = document.documentElement;
4950 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4956 var o = target.calcOffsetsTo(c);
4963 this.fireEvent('scrollto', this, options, e);
4965 Roo.get(c).scrollTo('top', options.value, true);
4978 * <span> icon </span>
4979 * <span> text </span>
4980 * <span>badge </span>
4984 * @class Roo.bootstrap.NavSidebarItem
4985 * @extends Roo.bootstrap.NavItem
4986 * Bootstrap Navbar.NavSidebarItem class
4987 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4988 * {Boolean} open is the menu open
4989 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4990 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4991 * {String} buttonSize (sm|md|lg)the extra classes for the button
4992 * {Boolean} showArrow show arrow next to the text (default true)
4994 * Create a new Navbar Button
4995 * @param {Object} config The config object
4997 Roo.bootstrap.NavSidebarItem = function(config){
4998 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5003 * The raw click event for the entire grid.
5004 * @param {Roo.EventObject} e
5009 * Fires when the active item active state changes
5010 * @param {Roo.bootstrap.NavSidebarItem} this
5011 * @param {boolean} state the new state
5019 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5021 badgeWeight : 'default',
5027 buttonWeight : 'default',
5033 getAutoCreate : function(){
5038 href : this.href || '#',
5044 if(this.buttonView){
5047 href : this.href || '#',
5048 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5061 cfg.cls += ' active';
5064 if (this.disabled) {
5065 cfg.cls += ' disabled';
5068 cfg.cls += ' open x-open';
5071 if (this.glyphicon || this.icon) {
5072 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5073 a.cn.push({ tag : 'i', cls : c }) ;
5076 if(!this.buttonView){
5079 html : this.html || ''
5086 if (this.badge !== '') {
5087 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5093 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5096 a.cls += ' dropdown-toggle treeview' ;
5102 initEvents : function()
5104 if (typeof (this.menu) != 'undefined') {
5105 this.menu.parentType = this.xtype;
5106 this.menu.triggerEl = this.el;
5107 this.menu = this.addxtype(Roo.apply({}, this.menu));
5110 this.el.on('click', this.onClick, this);
5112 if(this.badge !== ''){
5113 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5118 onClick : function(e)
5125 if(this.preventDefault){
5129 this.fireEvent('click', this, e);
5132 disable : function()
5134 this.setDisabled(true);
5139 this.setDisabled(false);
5142 setDisabled : function(state)
5144 if(this.disabled == state){
5148 this.disabled = state;
5151 this.el.addClass('disabled');
5155 this.el.removeClass('disabled');
5160 setActive : function(state)
5162 if(this.active == state){
5166 this.active = state;
5169 this.el.addClass('active');
5173 this.el.removeClass('active');
5178 isActive: function ()
5183 setBadge : function(str)
5189 this.badgeEl.dom.innerHTML = str;
5206 * @class Roo.bootstrap.Row
5207 * @extends Roo.bootstrap.Component
5208 * Bootstrap Row class (contains columns...)
5212 * @param {Object} config The config object
5215 Roo.bootstrap.Row = function(config){
5216 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5219 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5221 getAutoCreate : function(){
5240 * @class Roo.bootstrap.Element
5241 * @extends Roo.bootstrap.Component
5242 * Bootstrap Element class
5243 * @cfg {String} html contents of the element
5244 * @cfg {String} tag tag of the element
5245 * @cfg {String} cls class of the element
5246 * @cfg {Boolean} preventDefault (true|false) default false
5247 * @cfg {Boolean} clickable (true|false) default false
5250 * Create a new Element
5251 * @param {Object} config The config object
5254 Roo.bootstrap.Element = function(config){
5255 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5261 * When a element is chick
5262 * @param {Roo.bootstrap.Element} this
5263 * @param {Roo.EventObject} e
5269 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5274 preventDefault: false,
5277 getAutoCreate : function(){
5281 // cls: this.cls, double assign in parent class Component.js :: onRender
5288 initEvents: function()
5290 Roo.bootstrap.Element.superclass.initEvents.call(this);
5293 this.el.on('click', this.onClick, this);
5298 onClick : function(e)
5300 if(this.preventDefault){
5304 this.fireEvent('click', this, e);
5307 getValue : function()
5309 return this.el.dom.innerHTML;
5312 setValue : function(value)
5314 this.el.dom.innerHTML = value;
5329 * @class Roo.bootstrap.Pagination
5330 * @extends Roo.bootstrap.Component
5331 * Bootstrap Pagination class
5332 * @cfg {String} size xs | sm | md | lg
5333 * @cfg {Boolean} inverse false | true
5336 * Create a new Pagination
5337 * @param {Object} config The config object
5340 Roo.bootstrap.Pagination = function(config){
5341 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5344 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5350 getAutoCreate : function(){
5356 cfg.cls += ' inverse';
5362 cfg.cls += " " + this.cls;
5380 * @class Roo.bootstrap.PaginationItem
5381 * @extends Roo.bootstrap.Component
5382 * Bootstrap PaginationItem class
5383 * @cfg {String} html text
5384 * @cfg {String} href the link
5385 * @cfg {Boolean} preventDefault (true | false) default true
5386 * @cfg {Boolean} active (true | false) default false
5387 * @cfg {Boolean} disabled default false
5391 * Create a new PaginationItem
5392 * @param {Object} config The config object
5396 Roo.bootstrap.PaginationItem = function(config){
5397 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5402 * The raw click event for the entire grid.
5403 * @param {Roo.EventObject} e
5409 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5413 preventDefault: true,
5418 getAutoCreate : function(){
5424 href : this.href ? this.href : '#',
5425 html : this.html ? this.html : ''
5435 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5439 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5445 initEvents: function() {
5447 this.el.on('click', this.onClick, this);
5450 onClick : function(e)
5452 Roo.log('PaginationItem on click ');
5453 if(this.preventDefault){
5461 this.fireEvent('click', this, e);
5477 * @class Roo.bootstrap.Slider
5478 * @extends Roo.bootstrap.Component
5479 * Bootstrap Slider class
5482 * Create a new Slider
5483 * @param {Object} config The config object
5486 Roo.bootstrap.Slider = function(config){
5487 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5490 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5492 getAutoCreate : function(){
5496 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5500 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5512 * Ext JS Library 1.1.1
5513 * Copyright(c) 2006-2007, Ext JS, LLC.
5515 * Originally Released Under LGPL - original licence link has changed is not relivant.
5518 * <script type="text/javascript">
5523 * @class Roo.grid.ColumnModel
5524 * @extends Roo.util.Observable
5525 * This is the default implementation of a ColumnModel used by the Grid. It defines
5526 * the columns in the grid.
5529 var colModel = new Roo.grid.ColumnModel([
5530 {header: "Ticker", width: 60, sortable: true, locked: true},
5531 {header: "Company Name", width: 150, sortable: true},
5532 {header: "Market Cap.", width: 100, sortable: true},
5533 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5534 {header: "Employees", width: 100, sortable: true, resizable: false}
5539 * The config options listed for this class are options which may appear in each
5540 * individual column definition.
5541 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5543 * @param {Object} config An Array of column config objects. See this class's
5544 * config objects for details.
5546 Roo.grid.ColumnModel = function(config){
5548 * The config passed into the constructor
5550 this.config = config;
5553 // if no id, create one
5554 // if the column does not have a dataIndex mapping,
5555 // map it to the order it is in the config
5556 for(var i = 0, len = config.length; i < len; i++){
5558 if(typeof c.dataIndex == "undefined"){
5561 if(typeof c.renderer == "string"){
5562 c.renderer = Roo.util.Format[c.renderer];
5564 if(typeof c.id == "undefined"){
5567 if(c.editor && c.editor.xtype){
5568 c.editor = Roo.factory(c.editor, Roo.grid);
5570 if(c.editor && c.editor.isFormField){
5571 c.editor = new Roo.grid.GridEditor(c.editor);
5573 this.lookup[c.id] = c;
5577 * The width of columns which have no width specified (defaults to 100)
5580 this.defaultWidth = 100;
5583 * Default sortable of columns which have no sortable specified (defaults to false)
5586 this.defaultSortable = false;
5590 * @event widthchange
5591 * Fires when the width of a column changes.
5592 * @param {ColumnModel} this
5593 * @param {Number} columnIndex The column index
5594 * @param {Number} newWidth The new width
5596 "widthchange": true,
5598 * @event headerchange
5599 * Fires when the text of a header changes.
5600 * @param {ColumnModel} this
5601 * @param {Number} columnIndex The column index
5602 * @param {Number} newText The new header text
5604 "headerchange": true,
5606 * @event hiddenchange
5607 * Fires when a column is hidden or "unhidden".
5608 * @param {ColumnModel} this
5609 * @param {Number} columnIndex The column index
5610 * @param {Boolean} hidden true if hidden, false otherwise
5612 "hiddenchange": true,
5614 * @event columnmoved
5615 * Fires when a column is moved.
5616 * @param {ColumnModel} this
5617 * @param {Number} oldIndex
5618 * @param {Number} newIndex
5620 "columnmoved" : true,
5622 * @event columlockchange
5623 * Fires when a column's locked state is changed
5624 * @param {ColumnModel} this
5625 * @param {Number} colIndex
5626 * @param {Boolean} locked true if locked
5628 "columnlockchange" : true
5630 Roo.grid.ColumnModel.superclass.constructor.call(this);
5632 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5634 * @cfg {String} header The header text to display in the Grid view.
5637 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5638 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5639 * specified, the column's index is used as an index into the Record's data Array.
5642 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5643 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5646 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5647 * Defaults to the value of the {@link #defaultSortable} property.
5648 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5651 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5654 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5657 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5660 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5663 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5664 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5665 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5666 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5669 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5672 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5675 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5678 * @cfg {String} cursor (Optional)
5681 * @cfg {String} tooltip (Optional)
5684 * @cfg {Number} xs (Optional)
5687 * @cfg {Number} sm (Optional)
5690 * @cfg {Number} md (Optional)
5693 * @cfg {Number} lg (Optional)
5696 * Returns the id of the column at the specified index.
5697 * @param {Number} index The column index
5698 * @return {String} the id
5700 getColumnId : function(index){
5701 return this.config[index].id;
5705 * Returns the column for a specified id.
5706 * @param {String} id The column id
5707 * @return {Object} the column
5709 getColumnById : function(id){
5710 return this.lookup[id];
5715 * Returns the column for a specified dataIndex.
5716 * @param {String} dataIndex The column dataIndex
5717 * @return {Object|Boolean} the column or false if not found
5719 getColumnByDataIndex: function(dataIndex){
5720 var index = this.findColumnIndex(dataIndex);
5721 return index > -1 ? this.config[index] : false;
5725 * Returns the index for a specified column id.
5726 * @param {String} id The column id
5727 * @return {Number} the index, or -1 if not found
5729 getIndexById : function(id){
5730 for(var i = 0, len = this.config.length; i < len; i++){
5731 if(this.config[i].id == id){
5739 * Returns the index for a specified column dataIndex.
5740 * @param {String} dataIndex The column dataIndex
5741 * @return {Number} the index, or -1 if not found
5744 findColumnIndex : function(dataIndex){
5745 for(var i = 0, len = this.config.length; i < len; i++){
5746 if(this.config[i].dataIndex == dataIndex){
5754 moveColumn : function(oldIndex, newIndex){
5755 var c = this.config[oldIndex];
5756 this.config.splice(oldIndex, 1);
5757 this.config.splice(newIndex, 0, c);
5758 this.dataMap = null;
5759 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5762 isLocked : function(colIndex){
5763 return this.config[colIndex].locked === true;
5766 setLocked : function(colIndex, value, suppressEvent){
5767 if(this.isLocked(colIndex) == value){
5770 this.config[colIndex].locked = value;
5772 this.fireEvent("columnlockchange", this, colIndex, value);
5776 getTotalLockedWidth : function(){
5778 for(var i = 0; i < this.config.length; i++){
5779 if(this.isLocked(i) && !this.isHidden(i)){
5780 this.totalWidth += this.getColumnWidth(i);
5786 getLockedCount : function(){
5787 for(var i = 0, len = this.config.length; i < len; i++){
5788 if(!this.isLocked(i)){
5793 return this.config.length;
5797 * Returns the number of columns.
5800 getColumnCount : function(visibleOnly){
5801 if(visibleOnly === true){
5803 for(var i = 0, len = this.config.length; i < len; i++){
5804 if(!this.isHidden(i)){
5810 return this.config.length;
5814 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5815 * @param {Function} fn
5816 * @param {Object} scope (optional)
5817 * @return {Array} result
5819 getColumnsBy : function(fn, scope){
5821 for(var i = 0, len = this.config.length; i < len; i++){
5822 var c = this.config[i];
5823 if(fn.call(scope||this, c, i) === true){
5831 * Returns true if the specified column is sortable.
5832 * @param {Number} col The column index
5835 isSortable : function(col){
5836 if(typeof this.config[col].sortable == "undefined"){
5837 return this.defaultSortable;
5839 return this.config[col].sortable;
5843 * Returns the rendering (formatting) function defined for the column.
5844 * @param {Number} col The column index.
5845 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5847 getRenderer : function(col){
5848 if(!this.config[col].renderer){
5849 return Roo.grid.ColumnModel.defaultRenderer;
5851 return this.config[col].renderer;
5855 * Sets the rendering (formatting) function for a column.
5856 * @param {Number} col The column index
5857 * @param {Function} fn The function to use to process the cell's raw data
5858 * to return HTML markup for the grid view. The render function is called with
5859 * the following parameters:<ul>
5860 * <li>Data value.</li>
5861 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5862 * <li>css A CSS style string to apply to the table cell.</li>
5863 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5864 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5865 * <li>Row index</li>
5866 * <li>Column index</li>
5867 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5869 setRenderer : function(col, fn){
5870 this.config[col].renderer = fn;
5874 * Returns the width for the specified column.
5875 * @param {Number} col The column index
5878 getColumnWidth : function(col){
5879 return this.config[col].width * 1 || this.defaultWidth;
5883 * Sets the width for a column.
5884 * @param {Number} col The column index
5885 * @param {Number} width The new width
5887 setColumnWidth : function(col, width, suppressEvent){
5888 this.config[col].width = width;
5889 this.totalWidth = null;
5891 this.fireEvent("widthchange", this, col, width);
5896 * Returns the total width of all columns.
5897 * @param {Boolean} includeHidden True to include hidden column widths
5900 getTotalWidth : function(includeHidden){
5901 if(!this.totalWidth){
5902 this.totalWidth = 0;
5903 for(var i = 0, len = this.config.length; i < len; i++){
5904 if(includeHidden || !this.isHidden(i)){
5905 this.totalWidth += this.getColumnWidth(i);
5909 return this.totalWidth;
5913 * Returns the header for the specified column.
5914 * @param {Number} col The column index
5917 getColumnHeader : function(col){
5918 return this.config[col].header;
5922 * Sets the header for a column.
5923 * @param {Number} col The column index
5924 * @param {String} header The new header
5926 setColumnHeader : function(col, header){
5927 this.config[col].header = header;
5928 this.fireEvent("headerchange", this, col, header);
5932 * Returns the tooltip for the specified column.
5933 * @param {Number} col The column index
5936 getColumnTooltip : function(col){
5937 return this.config[col].tooltip;
5940 * Sets the tooltip for a column.
5941 * @param {Number} col The column index
5942 * @param {String} tooltip The new tooltip
5944 setColumnTooltip : function(col, tooltip){
5945 this.config[col].tooltip = tooltip;
5949 * Returns the dataIndex for the specified column.
5950 * @param {Number} col The column index
5953 getDataIndex : function(col){
5954 return this.config[col].dataIndex;
5958 * Sets the dataIndex for a column.
5959 * @param {Number} col The column index
5960 * @param {Number} dataIndex The new dataIndex
5962 setDataIndex : function(col, dataIndex){
5963 this.config[col].dataIndex = dataIndex;
5969 * Returns true if the cell is editable.
5970 * @param {Number} colIndex The column index
5971 * @param {Number} rowIndex The row index - this is nto actually used..?
5974 isCellEditable : function(colIndex, rowIndex){
5975 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5979 * Returns the editor defined for the cell/column.
5980 * return false or null to disable editing.
5981 * @param {Number} colIndex The column index
5982 * @param {Number} rowIndex The row index
5985 getCellEditor : function(colIndex, rowIndex){
5986 return this.config[colIndex].editor;
5990 * Sets if a column is editable.
5991 * @param {Number} col The column index
5992 * @param {Boolean} editable True if the column is editable
5994 setEditable : function(col, editable){
5995 this.config[col].editable = editable;
6000 * Returns true if the column is hidden.
6001 * @param {Number} colIndex The column index
6004 isHidden : function(colIndex){
6005 return this.config[colIndex].hidden;
6010 * Returns true if the column width cannot be changed
6012 isFixed : function(colIndex){
6013 return this.config[colIndex].fixed;
6017 * Returns true if the column can be resized
6020 isResizable : function(colIndex){
6021 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6024 * Sets if a column is hidden.
6025 * @param {Number} colIndex The column index
6026 * @param {Boolean} hidden True if the column is hidden
6028 setHidden : function(colIndex, hidden){
6029 this.config[colIndex].hidden = hidden;
6030 this.totalWidth = null;
6031 this.fireEvent("hiddenchange", this, colIndex, hidden);
6035 * Sets the editor for a column.
6036 * @param {Number} col The column index
6037 * @param {Object} editor The editor object
6039 setEditor : function(col, editor){
6040 this.config[col].editor = editor;
6044 Roo.grid.ColumnModel.defaultRenderer = function(value)
6046 if(typeof value == "object") {
6049 if(typeof value == "string" && value.length < 1){
6053 return String.format("{0}", value);
6056 // Alias for backwards compatibility
6057 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6060 * Ext JS Library 1.1.1
6061 * Copyright(c) 2006-2007, Ext JS, LLC.
6063 * Originally Released Under LGPL - original licence link has changed is not relivant.
6066 * <script type="text/javascript">
6070 * @class Roo.LoadMask
6071 * A simple utility class for generically masking elements while loading data. If the element being masked has
6072 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6073 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6074 * element's UpdateManager load indicator and will be destroyed after the initial load.
6076 * Create a new LoadMask
6077 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6078 * @param {Object} config The config object
6080 Roo.LoadMask = function(el, config){
6081 this.el = Roo.get(el);
6082 Roo.apply(this, config);
6084 this.store.on('beforeload', this.onBeforeLoad, this);
6085 this.store.on('load', this.onLoad, this);
6086 this.store.on('loadexception', this.onLoadException, this);
6087 this.removeMask = false;
6089 var um = this.el.getUpdateManager();
6090 um.showLoadIndicator = false; // disable the default indicator
6091 um.on('beforeupdate', this.onBeforeLoad, this);
6092 um.on('update', this.onLoad, this);
6093 um.on('failure', this.onLoad, this);
6094 this.removeMask = true;
6098 Roo.LoadMask.prototype = {
6100 * @cfg {Boolean} removeMask
6101 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6102 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6106 * The text to display in a centered loading message box (defaults to 'Loading...')
6110 * @cfg {String} msgCls
6111 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6113 msgCls : 'x-mask-loading',
6116 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6122 * Disables the mask to prevent it from being displayed
6124 disable : function(){
6125 this.disabled = true;
6129 * Enables the mask so that it can be displayed
6131 enable : function(){
6132 this.disabled = false;
6135 onLoadException : function()
6139 if (typeof(arguments[3]) != 'undefined') {
6140 Roo.MessageBox.alert("Error loading",arguments[3]);
6144 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6145 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6152 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6157 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6161 onBeforeLoad : function(){
6163 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6168 destroy : function(){
6170 this.store.un('beforeload', this.onBeforeLoad, this);
6171 this.store.un('load', this.onLoad, this);
6172 this.store.un('loadexception', this.onLoadException, this);
6174 var um = this.el.getUpdateManager();
6175 um.un('beforeupdate', this.onBeforeLoad, this);
6176 um.un('update', this.onLoad, this);
6177 um.un('failure', this.onLoad, this);
6188 * @class Roo.bootstrap.Table
6189 * @extends Roo.bootstrap.Component
6190 * Bootstrap Table class
6191 * @cfg {String} cls table class
6192 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6193 * @cfg {String} bgcolor Specifies the background color for a table
6194 * @cfg {Number} border Specifies whether the table cells should have borders or not
6195 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6196 * @cfg {Number} cellspacing Specifies the space between cells
6197 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6198 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6199 * @cfg {String} sortable Specifies that the table should be sortable
6200 * @cfg {String} summary Specifies a summary of the content of a table
6201 * @cfg {Number} width Specifies the width of a table
6202 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6204 * @cfg {boolean} striped Should the rows be alternative striped
6205 * @cfg {boolean} bordered Add borders to the table
6206 * @cfg {boolean} hover Add hover highlighting
6207 * @cfg {boolean} condensed Format condensed
6208 * @cfg {boolean} responsive Format condensed
6209 * @cfg {Boolean} loadMask (true|false) default false
6210 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6211 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6212 * @cfg {Boolean} rowSelection (true|false) default false
6213 * @cfg {Boolean} cellSelection (true|false) default false
6214 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6215 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6216 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6217 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6221 * Create a new Table
6222 * @param {Object} config The config object
6225 Roo.bootstrap.Table = function(config){
6226 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6231 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6232 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6233 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6234 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6236 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6238 this.sm.grid = this;
6239 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6240 this.sm = this.selModel;
6241 this.sm.xmodule = this.xmodule || false;
6244 if (this.cm && typeof(this.cm.config) == 'undefined') {
6245 this.colModel = new Roo.grid.ColumnModel(this.cm);
6246 this.cm = this.colModel;
6247 this.cm.xmodule = this.xmodule || false;
6250 this.store= Roo.factory(this.store, Roo.data);
6251 this.ds = this.store;
6252 this.ds.xmodule = this.xmodule || false;
6255 if (this.footer && this.store) {
6256 this.footer.dataSource = this.ds;
6257 this.footer = Roo.factory(this.footer);
6264 * Fires when a cell is clicked
6265 * @param {Roo.bootstrap.Table} this
6266 * @param {Roo.Element} el
6267 * @param {Number} rowIndex
6268 * @param {Number} columnIndex
6269 * @param {Roo.EventObject} e
6273 * @event celldblclick
6274 * Fires when a cell is double clicked
6275 * @param {Roo.bootstrap.Table} this
6276 * @param {Roo.Element} el
6277 * @param {Number} rowIndex
6278 * @param {Number} columnIndex
6279 * @param {Roo.EventObject} e
6281 "celldblclick" : true,
6284 * Fires when a row is clicked
6285 * @param {Roo.bootstrap.Table} this
6286 * @param {Roo.Element} el
6287 * @param {Number} rowIndex
6288 * @param {Roo.EventObject} e
6292 * @event rowdblclick
6293 * Fires when a row is double clicked
6294 * @param {Roo.bootstrap.Table} this
6295 * @param {Roo.Element} el
6296 * @param {Number} rowIndex
6297 * @param {Roo.EventObject} e
6299 "rowdblclick" : true,
6302 * Fires when a mouseover occur
6303 * @param {Roo.bootstrap.Table} this
6304 * @param {Roo.Element} el
6305 * @param {Number} rowIndex
6306 * @param {Number} columnIndex
6307 * @param {Roo.EventObject} e
6312 * Fires when a mouseout occur
6313 * @param {Roo.bootstrap.Table} this
6314 * @param {Roo.Element} el
6315 * @param {Number} rowIndex
6316 * @param {Number} columnIndex
6317 * @param {Roo.EventObject} e
6322 * Fires when a row is rendered, so you can change add a style to it.
6323 * @param {Roo.bootstrap.Table} this
6324 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6328 * @event rowsrendered
6329 * Fires when all the rows have been rendered
6330 * @param {Roo.bootstrap.Table} this
6332 'rowsrendered' : true,
6334 * @event contextmenu
6335 * The raw contextmenu event for the entire grid.
6336 * @param {Roo.EventObject} e
6338 "contextmenu" : true,
6340 * @event rowcontextmenu
6341 * Fires when a row is right clicked
6342 * @param {Roo.bootstrap.Table} this
6343 * @param {Number} rowIndex
6344 * @param {Roo.EventObject} e
6346 "rowcontextmenu" : true,
6348 * @event cellcontextmenu
6349 * Fires when a cell is right clicked
6350 * @param {Roo.bootstrap.Table} this
6351 * @param {Number} rowIndex
6352 * @param {Number} cellIndex
6353 * @param {Roo.EventObject} e
6355 "cellcontextmenu" : true,
6357 * @event headercontextmenu
6358 * Fires when a header is right clicked
6359 * @param {Roo.bootstrap.Table} this
6360 * @param {Number} columnIndex
6361 * @param {Roo.EventObject} e
6363 "headercontextmenu" : true
6367 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6393 rowSelection : false,
6394 cellSelection : false,
6397 // Roo.Element - the tbody
6399 // Roo.Element - thead element
6402 container: false, // used by gridpanel...
6408 auto_hide_footer : false,
6410 getAutoCreate : function()
6412 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6419 if (this.scrollBody) {
6420 cfg.cls += ' table-body-fixed';
6423 cfg.cls += ' table-striped';
6427 cfg.cls += ' table-hover';
6429 if (this.bordered) {
6430 cfg.cls += ' table-bordered';
6432 if (this.condensed) {
6433 cfg.cls += ' table-condensed';
6435 if (this.responsive) {
6436 cfg.cls += ' table-responsive';
6440 cfg.cls+= ' ' +this.cls;
6443 // this lot should be simplifed...
6456 ].forEach(function(k) {
6464 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6467 if(this.store || this.cm){
6468 if(this.headerShow){
6469 cfg.cn.push(this.renderHeader());
6472 cfg.cn.push(this.renderBody());
6474 if(this.footerShow){
6475 cfg.cn.push(this.renderFooter());
6477 // where does this come from?
6478 //cfg.cls+= ' TableGrid';
6481 return { cn : [ cfg ] };
6484 initEvents : function()
6486 if(!this.store || !this.cm){
6489 if (this.selModel) {
6490 this.selModel.initEvents();
6494 //Roo.log('initEvents with ds!!!!');
6496 this.mainBody = this.el.select('tbody', true).first();
6497 this.mainHead = this.el.select('thead', true).first();
6498 this.mainFoot = this.el.select('tfoot', true).first();
6504 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6505 e.on('click', _this.sort, _this);
6508 this.mainBody.on("click", this.onClick, this);
6509 this.mainBody.on("dblclick", this.onDblClick, this);
6511 // why is this done????? = it breaks dialogs??
6512 //this.parent().el.setStyle('position', 'relative');
6516 this.footer.parentId = this.id;
6517 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6520 this.el.select('tfoot tr td').first().addClass('hide');
6525 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6528 this.store.on('load', this.onLoad, this);
6529 this.store.on('beforeload', this.onBeforeLoad, this);
6530 this.store.on('update', this.onUpdate, this);
6531 this.store.on('add', this.onAdd, this);
6532 this.store.on("clear", this.clear, this);
6534 this.el.on("contextmenu", this.onContextMenu, this);
6536 this.mainBody.on('scroll', this.onBodyScroll, this);
6538 this.cm.on("headerchange", this.onHeaderChange, this);
6540 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6544 onContextMenu : function(e, t)
6546 this.processEvent("contextmenu", e);
6549 processEvent : function(name, e)
6551 if (name != 'touchstart' ) {
6552 this.fireEvent(name, e);
6555 var t = e.getTarget();
6557 var cell = Roo.get(t);
6563 if(cell.findParent('tfoot', false, true)){
6567 if(cell.findParent('thead', false, true)){
6569 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6570 cell = Roo.get(t).findParent('th', false, true);
6572 Roo.log("failed to find th in thead?");
6573 Roo.log(e.getTarget());
6578 var cellIndex = cell.dom.cellIndex;
6580 var ename = name == 'touchstart' ? 'click' : name;
6581 this.fireEvent("header" + ename, this, cellIndex, e);
6586 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6587 cell = Roo.get(t).findParent('td', false, true);
6589 Roo.log("failed to find th in tbody?");
6590 Roo.log(e.getTarget());
6595 var row = cell.findParent('tr', false, true);
6596 var cellIndex = cell.dom.cellIndex;
6597 var rowIndex = row.dom.rowIndex - 1;
6601 this.fireEvent("row" + name, this, rowIndex, e);
6605 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6611 onMouseover : function(e, el)
6613 var cell = Roo.get(el);
6619 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6620 cell = cell.findParent('td', false, true);
6623 var row = cell.findParent('tr', false, true);
6624 var cellIndex = cell.dom.cellIndex;
6625 var rowIndex = row.dom.rowIndex - 1; // start from 0
6627 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6631 onMouseout : function(e, el)
6633 var cell = Roo.get(el);
6639 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6640 cell = cell.findParent('td', false, true);
6643 var row = cell.findParent('tr', false, true);
6644 var cellIndex = cell.dom.cellIndex;
6645 var rowIndex = row.dom.rowIndex - 1; // start from 0
6647 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6651 onClick : function(e, el)
6653 var cell = Roo.get(el);
6655 if(!cell || (!this.cellSelection && !this.rowSelection)){
6659 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6660 cell = cell.findParent('td', false, true);
6663 if(!cell || typeof(cell) == 'undefined'){
6667 var row = cell.findParent('tr', false, true);
6669 if(!row || typeof(row) == 'undefined'){
6673 var cellIndex = cell.dom.cellIndex;
6674 var rowIndex = this.getRowIndex(row);
6676 // why??? - should these not be based on SelectionModel?
6677 if(this.cellSelection){
6678 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6681 if(this.rowSelection){
6682 this.fireEvent('rowclick', this, row, rowIndex, e);
6688 onDblClick : function(e,el)
6690 var cell = Roo.get(el);
6692 if(!cell || (!this.cellSelection && !this.rowSelection)){
6696 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6697 cell = cell.findParent('td', false, true);
6700 if(!cell || typeof(cell) == 'undefined'){
6704 var row = cell.findParent('tr', false, true);
6706 if(!row || typeof(row) == 'undefined'){
6710 var cellIndex = cell.dom.cellIndex;
6711 var rowIndex = this.getRowIndex(row);
6713 if(this.cellSelection){
6714 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6717 if(this.rowSelection){
6718 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6722 sort : function(e,el)
6724 var col = Roo.get(el);
6726 if(!col.hasClass('sortable')){
6730 var sort = col.attr('sort');
6733 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6737 this.store.sortInfo = {field : sort, direction : dir};
6740 Roo.log("calling footer first");
6741 this.footer.onClick('first');
6744 this.store.load({ params : { start : 0 } });
6748 renderHeader : function()
6756 this.totalWidth = 0;
6758 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6760 var config = cm.config[i];
6764 cls : 'x-hcol-' + i,
6766 html: cm.getColumnHeader(i)
6771 if(typeof(config.sortable) != 'undefined' && config.sortable){
6773 c.html = '<i class="glyphicon"></i>' + c.html;
6776 if(typeof(config.lgHeader) != 'undefined'){
6777 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6780 if(typeof(config.mdHeader) != 'undefined'){
6781 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6784 if(typeof(config.smHeader) != 'undefined'){
6785 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6788 if(typeof(config.xsHeader) != 'undefined'){
6789 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6796 if(typeof(config.tooltip) != 'undefined'){
6797 c.tooltip = config.tooltip;
6800 if(typeof(config.colspan) != 'undefined'){
6801 c.colspan = config.colspan;
6804 if(typeof(config.hidden) != 'undefined' && config.hidden){
6805 c.style += ' display:none;';
6808 if(typeof(config.dataIndex) != 'undefined'){
6809 c.sort = config.dataIndex;
6814 if(typeof(config.align) != 'undefined' && config.align.length){
6815 c.style += ' text-align:' + config.align + ';';
6818 if(typeof(config.width) != 'undefined'){
6819 c.style += ' width:' + config.width + 'px;';
6820 this.totalWidth += config.width;
6822 this.totalWidth += 100; // assume minimum of 100 per column?
6825 if(typeof(config.cls) != 'undefined'){
6826 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6829 ['xs','sm','md','lg'].map(function(size){
6831 if(typeof(config[size]) == 'undefined'){
6835 if (!config[size]) { // 0 = hidden
6836 c.cls += ' hidden-' + size;
6840 c.cls += ' col-' + size + '-' + config[size];
6850 renderBody : function()
6860 colspan : this.cm.getColumnCount()
6870 renderFooter : function()
6880 colspan : this.cm.getColumnCount()
6894 // Roo.log('ds onload');
6899 var ds = this.store;
6901 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6902 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6903 if (_this.store.sortInfo) {
6905 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6906 e.select('i', true).addClass(['glyphicon-arrow-up']);
6909 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6910 e.select('i', true).addClass(['glyphicon-arrow-down']);
6915 var tbody = this.mainBody;
6917 if(ds.getCount() > 0){
6918 ds.data.each(function(d,rowIndex){
6919 var row = this.renderRow(cm, ds, rowIndex);
6921 tbody.createChild(row);
6925 if(row.cellObjects.length){
6926 Roo.each(row.cellObjects, function(r){
6927 _this.renderCellObject(r);
6934 var tfoot = this.el.select('tfoot', true).first();
6936 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6938 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6940 var total = this.ds.getTotalCount();
6942 if(this.footer.pageSize < total){
6943 this.mainFoot.show();
6947 Roo.each(this.el.select('tbody td', true).elements, function(e){
6948 e.on('mouseover', _this.onMouseover, _this);
6951 Roo.each(this.el.select('tbody td', true).elements, function(e){
6952 e.on('mouseout', _this.onMouseout, _this);
6954 this.fireEvent('rowsrendered', this);
6960 onUpdate : function(ds,record)
6962 this.refreshRow(record);
6966 onRemove : function(ds, record, index, isUpdate){
6967 if(isUpdate !== true){
6968 this.fireEvent("beforerowremoved", this, index, record);
6970 var bt = this.mainBody.dom;
6972 var rows = this.el.select('tbody > tr', true).elements;
6974 if(typeof(rows[index]) != 'undefined'){
6975 bt.removeChild(rows[index].dom);
6978 // if(bt.rows[index]){
6979 // bt.removeChild(bt.rows[index]);
6982 if(isUpdate !== true){
6983 //this.stripeRows(index);
6984 //this.syncRowHeights(index, index);
6986 this.fireEvent("rowremoved", this, index, record);
6990 onAdd : function(ds, records, rowIndex)
6992 //Roo.log('on Add called');
6993 // - note this does not handle multiple adding very well..
6994 var bt = this.mainBody.dom;
6995 for (var i =0 ; i < records.length;i++) {
6996 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6997 //Roo.log(records[i]);
6998 //Roo.log(this.store.getAt(rowIndex+i));
6999 this.insertRow(this.store, rowIndex + i, false);
7006 refreshRow : function(record){
7007 var ds = this.store, index;
7008 if(typeof record == 'number'){
7010 record = ds.getAt(index);
7012 index = ds.indexOf(record);
7014 this.insertRow(ds, index, true);
7016 this.onRemove(ds, record, index+1, true);
7018 //this.syncRowHeights(index, index);
7020 this.fireEvent("rowupdated", this, index, record);
7023 insertRow : function(dm, rowIndex, isUpdate){
7026 this.fireEvent("beforerowsinserted", this, rowIndex);
7028 //var s = this.getScrollState();
7029 var row = this.renderRow(this.cm, this.store, rowIndex);
7030 // insert before rowIndex..
7031 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7035 if(row.cellObjects.length){
7036 Roo.each(row.cellObjects, function(r){
7037 _this.renderCellObject(r);
7042 this.fireEvent("rowsinserted", this, rowIndex);
7043 //this.syncRowHeights(firstRow, lastRow);
7044 //this.stripeRows(firstRow);
7051 getRowDom : function(rowIndex)
7053 var rows = this.el.select('tbody > tr', true).elements;
7055 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7058 // returns the object tree for a tr..
7061 renderRow : function(cm, ds, rowIndex)
7063 var d = ds.getAt(rowIndex);
7067 cls : 'x-row-' + rowIndex,
7071 var cellObjects = [];
7073 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7074 var config = cm.config[i];
7076 var renderer = cm.getRenderer(i);
7080 if(typeof(renderer) !== 'undefined'){
7081 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7083 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7084 // and are rendered into the cells after the row is rendered - using the id for the element.
7086 if(typeof(value) === 'object'){
7096 rowIndex : rowIndex,
7101 this.fireEvent('rowclass', this, rowcfg);
7105 cls : rowcfg.rowClass + ' x-col-' + i,
7107 html: (typeof(value) === 'object') ? '' : value
7114 if(typeof(config.colspan) != 'undefined'){
7115 td.colspan = config.colspan;
7118 if(typeof(config.hidden) != 'undefined' && config.hidden){
7119 td.style += ' display:none;';
7122 if(typeof(config.align) != 'undefined' && config.align.length){
7123 td.style += ' text-align:' + config.align + ';';
7125 if(typeof(config.valign) != 'undefined' && config.valign.length){
7126 td.style += ' vertical-align:' + config.valign + ';';
7129 if(typeof(config.width) != 'undefined'){
7130 td.style += ' width:' + config.width + 'px;';
7133 if(typeof(config.cursor) != 'undefined'){
7134 td.style += ' cursor:' + config.cursor + ';';
7137 if(typeof(config.cls) != 'undefined'){
7138 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7141 ['xs','sm','md','lg'].map(function(size){
7143 if(typeof(config[size]) == 'undefined'){
7147 if (!config[size]) { // 0 = hidden
7148 td.cls += ' hidden-' + size;
7152 td.cls += ' col-' + size + '-' + config[size];
7160 row.cellObjects = cellObjects;
7168 onBeforeLoad : function()
7177 this.el.select('tbody', true).first().dom.innerHTML = '';
7180 * Show or hide a row.
7181 * @param {Number} rowIndex to show or hide
7182 * @param {Boolean} state hide
7184 setRowVisibility : function(rowIndex, state)
7186 var bt = this.mainBody.dom;
7188 var rows = this.el.select('tbody > tr', true).elements;
7190 if(typeof(rows[rowIndex]) == 'undefined'){
7193 rows[rowIndex].dom.style.display = state ? '' : 'none';
7197 getSelectionModel : function(){
7199 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7201 return this.selModel;
7204 * Render the Roo.bootstrap object from renderder
7206 renderCellObject : function(r)
7210 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7212 var t = r.cfg.render(r.container);
7215 Roo.each(r.cfg.cn, function(c){
7217 container: t.getChildContainer(),
7220 _this.renderCellObject(child);
7225 getRowIndex : function(row)
7229 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7240 * Returns the grid's underlying element = used by panel.Grid
7241 * @return {Element} The element
7243 getGridEl : function(){
7247 * Forces a resize - used by panel.Grid
7248 * @return {Element} The element
7250 autoSize : function()
7252 //var ctr = Roo.get(this.container.dom.parentElement);
7253 var ctr = Roo.get(this.el.dom);
7255 var thd = this.getGridEl().select('thead',true).first();
7256 var tbd = this.getGridEl().select('tbody', true).first();
7257 var tfd = this.getGridEl().select('tfoot', true).first();
7259 var cw = ctr.getWidth();
7263 tbd.setSize(ctr.getWidth(),
7264 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7266 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7269 cw = Math.max(cw, this.totalWidth);
7270 this.getGridEl().select('tr',true).setWidth(cw);
7271 // resize 'expandable coloumn?
7273 return; // we doe not have a view in this design..
7276 onBodyScroll: function()
7278 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7280 this.mainHead.setStyle({
7281 'position' : 'relative',
7282 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7288 var scrollHeight = this.mainBody.dom.scrollHeight;
7290 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7292 var height = this.mainBody.getHeight();
7294 if(scrollHeight - height == scrollTop) {
7296 var total = this.ds.getTotalCount();
7298 if(this.footer.cursor + this.footer.pageSize < total){
7300 this.footer.ds.load({
7302 start : this.footer.cursor + this.footer.pageSize,
7303 limit : this.footer.pageSize
7313 onHeaderChange : function()
7315 var header = this.renderHeader();
7316 var table = this.el.select('table', true).first();
7318 this.mainHead.remove();
7319 this.mainHead = table.createChild(header, this.mainBody, false);
7322 onHiddenChange : function(colModel, colIndex, hidden)
7324 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7325 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7327 this.CSS.updateRule(thSelector, "display", "");
7328 this.CSS.updateRule(tdSelector, "display", "");
7331 this.CSS.updateRule(thSelector, "display", "none");
7332 this.CSS.updateRule(tdSelector, "display", "none");
7335 this.onHeaderChange();
7339 setColumnWidth: function(col_index, width)
7341 // width = "md-2 xs-2..."
7342 if(!this.colModel.config[col_index]) {
7346 var w = width.split(" ");
7348 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7350 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7353 for(var j = 0; j < w.length; j++) {
7359 var size_cls = w[j].split("-");
7361 if(!Number.isInteger(size_cls[1] * 1)) {
7365 if(!this.colModel.config[col_index][size_cls[0]]) {
7369 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7373 h_row[0].classList.replace(
7374 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7375 "col-"+size_cls[0]+"-"+size_cls[1]
7378 for(var i = 0; i < rows.length; i++) {
7380 var size_cls = w[j].split("-");
7382 if(!Number.isInteger(size_cls[1] * 1)) {
7386 if(!this.colModel.config[col_index][size_cls[0]]) {
7390 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7394 rows[i].classList.replace(
7395 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7396 "col-"+size_cls[0]+"-"+size_cls[1]
7400 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7415 * @class Roo.bootstrap.TableCell
7416 * @extends Roo.bootstrap.Component
7417 * Bootstrap TableCell class
7418 * @cfg {String} html cell contain text
7419 * @cfg {String} cls cell class
7420 * @cfg {String} tag cell tag (td|th) default td
7421 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7422 * @cfg {String} align Aligns the content in a cell
7423 * @cfg {String} axis Categorizes cells
7424 * @cfg {String} bgcolor Specifies the background color of a cell
7425 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7426 * @cfg {Number} colspan Specifies the number of columns a cell should span
7427 * @cfg {String} headers Specifies one or more header cells a cell is related to
7428 * @cfg {Number} height Sets the height of a cell
7429 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7430 * @cfg {Number} rowspan Sets the number of rows a cell should span
7431 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7432 * @cfg {String} valign Vertical aligns the content in a cell
7433 * @cfg {Number} width Specifies the width of a cell
7436 * Create a new TableCell
7437 * @param {Object} config The config object
7440 Roo.bootstrap.TableCell = function(config){
7441 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7444 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7464 getAutoCreate : function(){
7465 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7485 cfg.align=this.align
7491 cfg.bgcolor=this.bgcolor
7494 cfg.charoff=this.charoff
7497 cfg.colspan=this.colspan
7500 cfg.headers=this.headers
7503 cfg.height=this.height
7506 cfg.nowrap=this.nowrap
7509 cfg.rowspan=this.rowspan
7512 cfg.scope=this.scope
7515 cfg.valign=this.valign
7518 cfg.width=this.width
7537 * @class Roo.bootstrap.TableRow
7538 * @extends Roo.bootstrap.Component
7539 * Bootstrap TableRow class
7540 * @cfg {String} cls row class
7541 * @cfg {String} align Aligns the content in a table row
7542 * @cfg {String} bgcolor Specifies a background color for a table row
7543 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7544 * @cfg {String} valign Vertical aligns the content in a table row
7547 * Create a new TableRow
7548 * @param {Object} config The config object
7551 Roo.bootstrap.TableRow = function(config){
7552 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7555 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7563 getAutoCreate : function(){
7564 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7574 cfg.align = this.align;
7577 cfg.bgcolor = this.bgcolor;
7580 cfg.charoff = this.charoff;
7583 cfg.valign = this.valign;
7601 * @class Roo.bootstrap.TableBody
7602 * @extends Roo.bootstrap.Component
7603 * Bootstrap TableBody class
7604 * @cfg {String} cls element class
7605 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7606 * @cfg {String} align Aligns the content inside the element
7607 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7608 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7611 * Create a new TableBody
7612 * @param {Object} config The config object
7615 Roo.bootstrap.TableBody = function(config){
7616 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7619 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7627 getAutoCreate : function(){
7628 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7642 cfg.align = this.align;
7645 cfg.charoff = this.charoff;
7648 cfg.valign = this.valign;
7655 // initEvents : function()
7662 // this.store = Roo.factory(this.store, Roo.data);
7663 // this.store.on('load', this.onLoad, this);
7665 // this.store.load();
7669 // onLoad: function ()
7671 // this.fireEvent('load', this);
7681 * Ext JS Library 1.1.1
7682 * Copyright(c) 2006-2007, Ext JS, LLC.
7684 * Originally Released Under LGPL - original licence link has changed is not relivant.
7687 * <script type="text/javascript">
7690 // as we use this in bootstrap.
7691 Roo.namespace('Roo.form');
7693 * @class Roo.form.Action
7694 * Internal Class used to handle form actions
7696 * @param {Roo.form.BasicForm} el The form element or its id
7697 * @param {Object} config Configuration options
7702 // define the action interface
7703 Roo.form.Action = function(form, options){
7705 this.options = options || {};
7708 * Client Validation Failed
7711 Roo.form.Action.CLIENT_INVALID = 'client';
7713 * Server Validation Failed
7716 Roo.form.Action.SERVER_INVALID = 'server';
7718 * Connect to Server Failed
7721 Roo.form.Action.CONNECT_FAILURE = 'connect';
7723 * Reading Data from Server Failed
7726 Roo.form.Action.LOAD_FAILURE = 'load';
7728 Roo.form.Action.prototype = {
7730 failureType : undefined,
7731 response : undefined,
7735 run : function(options){
7740 success : function(response){
7745 handleResponse : function(response){
7749 // default connection failure
7750 failure : function(response){
7752 this.response = response;
7753 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7754 this.form.afterAction(this, false);
7757 processResponse : function(response){
7758 this.response = response;
7759 if(!response.responseText){
7762 this.result = this.handleResponse(response);
7766 // utility functions used internally
7767 getUrl : function(appendParams){
7768 var url = this.options.url || this.form.url || this.form.el.dom.action;
7770 var p = this.getParams();
7772 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7778 getMethod : function(){
7779 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7782 getParams : function(){
7783 var bp = this.form.baseParams;
7784 var p = this.options.params;
7786 if(typeof p == "object"){
7787 p = Roo.urlEncode(Roo.applyIf(p, bp));
7788 }else if(typeof p == 'string' && bp){
7789 p += '&' + Roo.urlEncode(bp);
7792 p = Roo.urlEncode(bp);
7797 createCallback : function(){
7799 success: this.success,
7800 failure: this.failure,
7802 timeout: (this.form.timeout*1000),
7803 upload: this.form.fileUpload ? this.success : undefined
7808 Roo.form.Action.Submit = function(form, options){
7809 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7812 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7815 haveProgress : false,
7816 uploadComplete : false,
7818 // uploadProgress indicator.
7819 uploadProgress : function()
7821 if (!this.form.progressUrl) {
7825 if (!this.haveProgress) {
7826 Roo.MessageBox.progress("Uploading", "Uploading");
7828 if (this.uploadComplete) {
7829 Roo.MessageBox.hide();
7833 this.haveProgress = true;
7835 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7837 var c = new Roo.data.Connection();
7839 url : this.form.progressUrl,
7844 success : function(req){
7845 //console.log(data);
7849 rdata = Roo.decode(req.responseText)
7851 Roo.log("Invalid data from server..");
7855 if (!rdata || !rdata.success) {
7857 Roo.MessageBox.alert(Roo.encode(rdata));
7860 var data = rdata.data;
7862 if (this.uploadComplete) {
7863 Roo.MessageBox.hide();
7868 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7869 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7872 this.uploadProgress.defer(2000,this);
7875 failure: function(data) {
7876 Roo.log('progress url failed ');
7887 // run get Values on the form, so it syncs any secondary forms.
7888 this.form.getValues();
7890 var o = this.options;
7891 var method = this.getMethod();
7892 var isPost = method == 'POST';
7893 if(o.clientValidation === false || this.form.isValid()){
7895 if (this.form.progressUrl) {
7896 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7897 (new Date() * 1) + '' + Math.random());
7902 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7903 form:this.form.el.dom,
7904 url:this.getUrl(!isPost),
7906 params:isPost ? this.getParams() : null,
7907 isUpload: this.form.fileUpload,
7908 formData : this.form.formData
7911 this.uploadProgress();
7913 }else if (o.clientValidation !== false){ // client validation failed
7914 this.failureType = Roo.form.Action.CLIENT_INVALID;
7915 this.form.afterAction(this, false);
7919 success : function(response)
7921 this.uploadComplete= true;
7922 if (this.haveProgress) {
7923 Roo.MessageBox.hide();
7927 var result = this.processResponse(response);
7928 if(result === true || result.success){
7929 this.form.afterAction(this, true);
7933 this.form.markInvalid(result.errors);
7934 this.failureType = Roo.form.Action.SERVER_INVALID;
7936 this.form.afterAction(this, false);
7938 failure : function(response)
7940 this.uploadComplete= true;
7941 if (this.haveProgress) {
7942 Roo.MessageBox.hide();
7945 this.response = response;
7946 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7947 this.form.afterAction(this, false);
7950 handleResponse : function(response){
7951 if(this.form.errorReader){
7952 var rs = this.form.errorReader.read(response);
7955 for(var i = 0, len = rs.records.length; i < len; i++) {
7956 var r = rs.records[i];
7960 if(errors.length < 1){
7964 success : rs.success,
7970 ret = Roo.decode(response.responseText);
7974 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7984 Roo.form.Action.Load = function(form, options){
7985 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7986 this.reader = this.form.reader;
7989 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7994 Roo.Ajax.request(Roo.apply(
7995 this.createCallback(), {
7996 method:this.getMethod(),
7997 url:this.getUrl(false),
7998 params:this.getParams()
8002 success : function(response){
8004 var result = this.processResponse(response);
8005 if(result === true || !result.success || !result.data){
8006 this.failureType = Roo.form.Action.LOAD_FAILURE;
8007 this.form.afterAction(this, false);
8010 this.form.clearInvalid();
8011 this.form.setValues(result.data);
8012 this.form.afterAction(this, true);
8015 handleResponse : function(response){
8016 if(this.form.reader){
8017 var rs = this.form.reader.read(response);
8018 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8020 success : rs.success,
8024 return Roo.decode(response.responseText);
8028 Roo.form.Action.ACTION_TYPES = {
8029 'load' : Roo.form.Action.Load,
8030 'submit' : Roo.form.Action.Submit
8039 * @class Roo.bootstrap.Form
8040 * @extends Roo.bootstrap.Component
8041 * Bootstrap Form class
8042 * @cfg {String} method GET | POST (default POST)
8043 * @cfg {String} labelAlign top | left (default top)
8044 * @cfg {String} align left | right - for navbars
8045 * @cfg {Boolean} loadMask load mask when submit (default true)
8050 * @param {Object} config The config object
8054 Roo.bootstrap.Form = function(config){
8056 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8058 Roo.bootstrap.Form.popover.apply();
8062 * @event clientvalidation
8063 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8064 * @param {Form} this
8065 * @param {Boolean} valid true if the form has passed client-side validation
8067 clientvalidation: true,
8069 * @event beforeaction
8070 * Fires before any action is performed. Return false to cancel the action.
8071 * @param {Form} this
8072 * @param {Action} action The action to be performed
8076 * @event actionfailed
8077 * Fires when an action fails.
8078 * @param {Form} this
8079 * @param {Action} action The action that failed
8081 actionfailed : true,
8083 * @event actioncomplete
8084 * Fires when an action is completed.
8085 * @param {Form} this
8086 * @param {Action} action The action that completed
8088 actioncomplete : true
8092 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8095 * @cfg {String} method
8096 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8101 * The URL to use for form actions if one isn't supplied in the action options.
8104 * @cfg {Boolean} fileUpload
8105 * Set to true if this form is a file upload.
8109 * @cfg {Object} baseParams
8110 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8114 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8118 * @cfg {Sting} align (left|right) for navbar forms
8123 activeAction : null,
8126 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8127 * element by passing it or its id or mask the form itself by passing in true.
8130 waitMsgTarget : false,
8135 * @cfg {Boolean} errorMask (true|false) default false
8140 * @cfg {Number} maskOffset Default 100
8145 * @cfg {Boolean} maskBody
8149 getAutoCreate : function(){
8153 method : this.method || 'POST',
8154 id : this.id || Roo.id(),
8157 if (this.parent().xtype.match(/^Nav/)) {
8158 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8162 if (this.labelAlign == 'left' ) {
8163 cfg.cls += ' form-horizontal';
8169 initEvents : function()
8171 this.el.on('submit', this.onSubmit, this);
8172 // this was added as random key presses on the form where triggering form submit.
8173 this.el.on('keypress', function(e) {
8174 if (e.getCharCode() != 13) {
8177 // we might need to allow it for textareas.. and some other items.
8178 // check e.getTarget().
8180 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8184 Roo.log("keypress blocked");
8192 onSubmit : function(e){
8197 * Returns true if client-side validation on the form is successful.
8200 isValid : function(){
8201 var items = this.getItems();
8205 items.each(function(f){
8211 Roo.log('invalid field: ' + f.name);
8215 if(!target && f.el.isVisible(true)){
8221 if(this.errorMask && !valid){
8222 Roo.bootstrap.Form.popover.mask(this, target);
8229 * Returns true if any fields in this form have changed since their original load.
8232 isDirty : function(){
8234 var items = this.getItems();
8235 items.each(function(f){
8245 * Performs a predefined action (submit or load) or custom actions you define on this form.
8246 * @param {String} actionName The name of the action type
8247 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8248 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8249 * accept other config options):
8251 Property Type Description
8252 ---------------- --------------- ----------------------------------------------------------------------------------
8253 url String The url for the action (defaults to the form's url)
8254 method String The form method to use (defaults to the form's method, or POST if not defined)
8255 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8256 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8257 validate the form on the client (defaults to false)
8259 * @return {BasicForm} this
8261 doAction : function(action, options){
8262 if(typeof action == 'string'){
8263 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8265 if(this.fireEvent('beforeaction', this, action) !== false){
8266 this.beforeAction(action);
8267 action.run.defer(100, action);
8273 beforeAction : function(action){
8274 var o = action.options;
8279 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8281 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8284 // not really supported yet.. ??
8286 //if(this.waitMsgTarget === true){
8287 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8288 //}else if(this.waitMsgTarget){
8289 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8290 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8292 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8298 afterAction : function(action, success){
8299 this.activeAction = null;
8300 var o = action.options;
8305 Roo.get(document.body).unmask();
8311 //if(this.waitMsgTarget === true){
8312 // this.el.unmask();
8313 //}else if(this.waitMsgTarget){
8314 // this.waitMsgTarget.unmask();
8316 // Roo.MessageBox.updateProgress(1);
8317 // Roo.MessageBox.hide();
8324 Roo.callback(o.success, o.scope, [this, action]);
8325 this.fireEvent('actioncomplete', this, action);
8329 // failure condition..
8330 // we have a scenario where updates need confirming.
8331 // eg. if a locking scenario exists..
8332 // we look for { errors : { needs_confirm : true }} in the response.
8334 (typeof(action.result) != 'undefined') &&
8335 (typeof(action.result.errors) != 'undefined') &&
8336 (typeof(action.result.errors.needs_confirm) != 'undefined')
8339 Roo.log("not supported yet");
8342 Roo.MessageBox.confirm(
8343 "Change requires confirmation",
8344 action.result.errorMsg,
8349 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8359 Roo.callback(o.failure, o.scope, [this, action]);
8360 // show an error message if no failed handler is set..
8361 if (!this.hasListener('actionfailed')) {
8362 Roo.log("need to add dialog support");
8364 Roo.MessageBox.alert("Error",
8365 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8366 action.result.errorMsg :
8367 "Saving Failed, please check your entries or try again"
8372 this.fireEvent('actionfailed', this, action);
8377 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8378 * @param {String} id The value to search for
8381 findField : function(id){
8382 var items = this.getItems();
8383 var field = items.get(id);
8385 items.each(function(f){
8386 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8393 return field || null;
8396 * Mark fields in this form invalid in bulk.
8397 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8398 * @return {BasicForm} this
8400 markInvalid : function(errors){
8401 if(errors instanceof Array){
8402 for(var i = 0, len = errors.length; i < len; i++){
8403 var fieldError = errors[i];
8404 var f = this.findField(fieldError.id);
8406 f.markInvalid(fieldError.msg);
8412 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8413 field.markInvalid(errors[id]);
8417 //Roo.each(this.childForms || [], function (f) {
8418 // f.markInvalid(errors);
8425 * Set values for fields in this form in bulk.
8426 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8427 * @return {BasicForm} this
8429 setValues : function(values){
8430 if(values instanceof Array){ // array of objects
8431 for(var i = 0, len = values.length; i < len; i++){
8433 var f = this.findField(v.id);
8435 f.setValue(v.value);
8436 if(this.trackResetOnLoad){
8437 f.originalValue = f.getValue();
8441 }else{ // object hash
8444 if(typeof values[id] != 'function' && (field = this.findField(id))){
8446 if (field.setFromData &&
8448 field.displayField &&
8449 // combos' with local stores can
8450 // be queried via setValue()
8451 // to set their value..
8452 (field.store && !field.store.isLocal)
8456 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8457 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8458 field.setFromData(sd);
8460 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8462 field.setFromData(values);
8465 field.setValue(values[id]);
8469 if(this.trackResetOnLoad){
8470 field.originalValue = field.getValue();
8476 //Roo.each(this.childForms || [], function (f) {
8477 // f.setValues(values);
8484 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8485 * they are returned as an array.
8486 * @param {Boolean} asString
8489 getValues : function(asString){
8490 //if (this.childForms) {
8491 // copy values from the child forms
8492 // Roo.each(this.childForms, function (f) {
8493 // this.setValues(f.getValues());
8499 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8500 if(asString === true){
8503 return Roo.urlDecode(fs);
8507 * Returns the fields in this form as an object with key/value pairs.
8508 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8511 getFieldValues : function(with_hidden)
8513 var items = this.getItems();
8515 items.each(function(f){
8521 var v = f.getValue();
8523 if (f.inputType =='radio') {
8524 if (typeof(ret[f.getName()]) == 'undefined') {
8525 ret[f.getName()] = ''; // empty..
8528 if (!f.el.dom.checked) {
8536 if(f.xtype == 'MoneyField'){
8537 ret[f.currencyName] = f.getCurrency();
8540 // not sure if this supported any more..
8541 if ((typeof(v) == 'object') && f.getRawValue) {
8542 v = f.getRawValue() ; // dates..
8544 // combo boxes where name != hiddenName...
8545 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8546 ret[f.name] = f.getRawValue();
8548 ret[f.getName()] = v;
8555 * Clears all invalid messages in this form.
8556 * @return {BasicForm} this
8558 clearInvalid : function(){
8559 var items = this.getItems();
8561 items.each(function(f){
8570 * @return {BasicForm} this
8573 var items = this.getItems();
8574 items.each(function(f){
8578 Roo.each(this.childForms || [], function (f) {
8586 getItems : function()
8588 var r=new Roo.util.MixedCollection(false, function(o){
8589 return o.id || (o.id = Roo.id());
8591 var iter = function(el) {
8598 Roo.each(el.items,function(e) {
8607 hideFields : function(items)
8609 Roo.each(items, function(i){
8611 var f = this.findField(i);
8622 showFields : function(items)
8624 Roo.each(items, function(i){
8626 var f = this.findField(i);
8639 Roo.apply(Roo.bootstrap.Form, {
8666 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8667 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8668 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8669 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8672 this.maskEl.top.enableDisplayMode("block");
8673 this.maskEl.left.enableDisplayMode("block");
8674 this.maskEl.bottom.enableDisplayMode("block");
8675 this.maskEl.right.enableDisplayMode("block");
8677 this.toolTip = new Roo.bootstrap.Tooltip({
8678 cls : 'roo-form-error-popover',
8680 'left' : ['r-l', [-2,0], 'right'],
8681 'right' : ['l-r', [2,0], 'left'],
8682 'bottom' : ['tl-bl', [0,2], 'top'],
8683 'top' : [ 'bl-tl', [0,-2], 'bottom']
8687 this.toolTip.render(Roo.get(document.body));
8689 this.toolTip.el.enableDisplayMode("block");
8691 Roo.get(document.body).on('click', function(){
8695 Roo.get(document.body).on('touchstart', function(){
8699 this.isApplied = true
8702 mask : function(form, target)
8706 this.target = target;
8708 if(!this.form.errorMask || !target.el){
8712 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8714 Roo.log(scrollable);
8716 var ot = this.target.el.calcOffsetsTo(scrollable);
8718 var scrollTo = ot[1] - this.form.maskOffset;
8720 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8722 scrollable.scrollTo('top', scrollTo);
8724 var box = this.target.el.getBox();
8726 var zIndex = Roo.bootstrap.Modal.zIndex++;
8729 this.maskEl.top.setStyle('position', 'absolute');
8730 this.maskEl.top.setStyle('z-index', zIndex);
8731 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8732 this.maskEl.top.setLeft(0);
8733 this.maskEl.top.setTop(0);
8734 this.maskEl.top.show();
8736 this.maskEl.left.setStyle('position', 'absolute');
8737 this.maskEl.left.setStyle('z-index', zIndex);
8738 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8739 this.maskEl.left.setLeft(0);
8740 this.maskEl.left.setTop(box.y - this.padding);
8741 this.maskEl.left.show();
8743 this.maskEl.bottom.setStyle('position', 'absolute');
8744 this.maskEl.bottom.setStyle('z-index', zIndex);
8745 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8746 this.maskEl.bottom.setLeft(0);
8747 this.maskEl.bottom.setTop(box.bottom + this.padding);
8748 this.maskEl.bottom.show();
8750 this.maskEl.right.setStyle('position', 'absolute');
8751 this.maskEl.right.setStyle('z-index', zIndex);
8752 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8753 this.maskEl.right.setLeft(box.right + this.padding);
8754 this.maskEl.right.setTop(box.y - this.padding);
8755 this.maskEl.right.show();
8757 this.toolTip.bindEl = this.target.el;
8759 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8761 var tip = this.target.blankText;
8763 if(this.target.getValue() !== '' ) {
8765 if (this.target.invalidText.length) {
8766 tip = this.target.invalidText;
8767 } else if (this.target.regexText.length){
8768 tip = this.target.regexText;
8772 this.toolTip.show(tip);
8774 this.intervalID = window.setInterval(function() {
8775 Roo.bootstrap.Form.popover.unmask();
8778 window.onwheel = function(){ return false;};
8780 (function(){ this.isMasked = true; }).defer(500, this);
8786 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8790 this.maskEl.top.setStyle('position', 'absolute');
8791 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8792 this.maskEl.top.hide();
8794 this.maskEl.left.setStyle('position', 'absolute');
8795 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8796 this.maskEl.left.hide();
8798 this.maskEl.bottom.setStyle('position', 'absolute');
8799 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8800 this.maskEl.bottom.hide();
8802 this.maskEl.right.setStyle('position', 'absolute');
8803 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8804 this.maskEl.right.hide();
8806 this.toolTip.hide();
8808 this.toolTip.el.hide();
8810 window.onwheel = function(){ return true;};
8812 if(this.intervalID){
8813 window.clearInterval(this.intervalID);
8814 this.intervalID = false;
8817 this.isMasked = false;
8827 * Ext JS Library 1.1.1
8828 * Copyright(c) 2006-2007, Ext JS, LLC.
8830 * Originally Released Under LGPL - original licence link has changed is not relivant.
8833 * <script type="text/javascript">
8836 * @class Roo.form.VTypes
8837 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8840 Roo.form.VTypes = function(){
8841 // closure these in so they are only created once.
8842 var alpha = /^[a-zA-Z_]+$/;
8843 var alphanum = /^[a-zA-Z0-9_]+$/;
8844 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8845 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8847 // All these messages and functions are configurable
8850 * The function used to validate email addresses
8851 * @param {String} value The email address
8853 'email' : function(v){
8854 return email.test(v);
8857 * The error text to display when the email validation function returns false
8860 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8862 * The keystroke filter mask to be applied on email input
8865 'emailMask' : /[a-z0-9_\.\-@]/i,
8868 * The function used to validate URLs
8869 * @param {String} value The URL
8871 'url' : function(v){
8875 * The error text to display when the url validation function returns false
8878 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8881 * The function used to validate alpha values
8882 * @param {String} value The value
8884 'alpha' : function(v){
8885 return alpha.test(v);
8888 * The error text to display when the alpha validation function returns false
8891 'alphaText' : 'This field should only contain letters and _',
8893 * The keystroke filter mask to be applied on alpha input
8896 'alphaMask' : /[a-z_]/i,
8899 * The function used to validate alphanumeric values
8900 * @param {String} value The value
8902 'alphanum' : function(v){
8903 return alphanum.test(v);
8906 * The error text to display when the alphanumeric validation function returns false
8909 'alphanumText' : 'This field should only contain letters, numbers and _',
8911 * The keystroke filter mask to be applied on alphanumeric input
8914 'alphanumMask' : /[a-z0-9_]/i
8924 * @class Roo.bootstrap.Input
8925 * @extends Roo.bootstrap.Component
8926 * Bootstrap Input class
8927 * @cfg {Boolean} disabled is it disabled
8928 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8929 * @cfg {String} name name of the input
8930 * @cfg {string} fieldLabel - the label associated
8931 * @cfg {string} placeholder - placeholder to put in text.
8932 * @cfg {string} before - input group add on before
8933 * @cfg {string} after - input group add on after
8934 * @cfg {string} size - (lg|sm) or leave empty..
8935 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8936 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8937 * @cfg {Number} md colspan out of 12 for computer-sized screens
8938 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8939 * @cfg {string} value default value of the input
8940 * @cfg {Number} labelWidth set the width of label
8941 * @cfg {Number} labellg set the width of label (1-12)
8942 * @cfg {Number} labelmd set the width of label (1-12)
8943 * @cfg {Number} labelsm set the width of label (1-12)
8944 * @cfg {Number} labelxs set the width of label (1-12)
8945 * @cfg {String} labelAlign (top|left)
8946 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8947 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8948 * @cfg {String} indicatorpos (left|right) default left
8949 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8950 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8952 * @cfg {String} align (left|center|right) Default left
8953 * @cfg {Boolean} forceFeedback (true|false) Default false
8956 * Create a new Input
8957 * @param {Object} config The config object
8960 Roo.bootstrap.Input = function(config){
8962 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8967 * Fires when this field receives input focus.
8968 * @param {Roo.form.Field} this
8973 * Fires when this field loses input focus.
8974 * @param {Roo.form.Field} this
8979 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8980 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8981 * @param {Roo.form.Field} this
8982 * @param {Roo.EventObject} e The event object
8987 * Fires just before the field blurs if the field value has changed.
8988 * @param {Roo.form.Field} this
8989 * @param {Mixed} newValue The new value
8990 * @param {Mixed} oldValue The original value
8995 * Fires after the field has been marked as invalid.
8996 * @param {Roo.form.Field} this
8997 * @param {String} msg The validation message
9002 * Fires after the field has been validated with no errors.
9003 * @param {Roo.form.Field} this
9008 * Fires after the key up
9009 * @param {Roo.form.Field} this
9010 * @param {Roo.EventObject} e The event Object
9016 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9018 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9019 automatic validation (defaults to "keyup").
9021 validationEvent : "keyup",
9023 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9025 validateOnBlur : true,
9027 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9029 validationDelay : 250,
9031 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9033 focusClass : "x-form-focus", // not needed???
9037 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9039 invalidClass : "has-warning",
9042 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9044 validClass : "has-success",
9047 * @cfg {Boolean} hasFeedback (true|false) default true
9052 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9054 invalidFeedbackClass : "glyphicon-warning-sign",
9057 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9059 validFeedbackClass : "glyphicon-ok",
9062 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9064 selectOnFocus : false,
9067 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9071 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9076 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9078 disableKeyFilter : false,
9081 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9085 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9089 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9091 blankText : "Please complete this mandatory field",
9094 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9098 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9100 maxLength : Number.MAX_VALUE,
9102 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9104 minLengthText : "The minimum length for this field is {0}",
9106 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9108 maxLengthText : "The maximum length for this field is {0}",
9112 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9113 * If available, this function will be called only after the basic validators all return true, and will be passed the
9114 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9118 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9119 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9120 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9124 * @cfg {String} regexText -- Depricated - use Invalid Text
9129 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9135 autocomplete: false,
9154 formatedValue : false,
9155 forceFeedback : false,
9157 indicatorpos : 'left',
9167 parentLabelAlign : function()
9170 while (parent.parent()) {
9171 parent = parent.parent();
9172 if (typeof(parent.labelAlign) !='undefined') {
9173 return parent.labelAlign;
9180 getAutoCreate : function()
9182 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9188 if(this.inputType != 'hidden'){
9189 cfg.cls = 'form-group' //input-group
9195 type : this.inputType,
9197 cls : 'form-control',
9198 placeholder : this.placeholder || '',
9199 autocomplete : this.autocomplete || 'new-password'
9202 if(this.capture.length){
9203 input.capture = this.capture;
9206 if(this.accept.length){
9207 input.accept = this.accept + "/*";
9211 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9214 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9215 input.maxLength = this.maxLength;
9218 if (this.disabled) {
9219 input.disabled=true;
9222 if (this.readOnly) {
9223 input.readonly=true;
9227 input.name = this.name;
9231 input.cls += ' input-' + this.size;
9235 ['xs','sm','md','lg'].map(function(size){
9236 if (settings[size]) {
9237 cfg.cls += ' col-' + size + '-' + settings[size];
9241 var inputblock = input;
9245 cls: 'glyphicon form-control-feedback'
9248 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9251 cls : 'has-feedback',
9259 if (this.before || this.after) {
9262 cls : 'input-group',
9266 if (this.before && typeof(this.before) == 'string') {
9268 inputblock.cn.push({
9270 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9274 if (this.before && typeof(this.before) == 'object') {
9275 this.before = Roo.factory(this.before);
9277 inputblock.cn.push({
9279 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9280 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9284 inputblock.cn.push(input);
9286 if (this.after && typeof(this.after) == 'string') {
9287 inputblock.cn.push({
9289 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9293 if (this.after && typeof(this.after) == 'object') {
9294 this.after = Roo.factory(this.after);
9296 inputblock.cn.push({
9298 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9299 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9303 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9304 inputblock.cls += ' has-feedback';
9305 inputblock.cn.push(feedback);
9310 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9311 tooltip : 'This field is required'
9313 if (Roo.bootstrap.version == 4) {
9316 style : 'display-none'
9319 if (align ==='left' && this.fieldLabel.length) {
9321 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9328 cls : 'control-label col-form-label',
9329 html : this.fieldLabel
9340 var labelCfg = cfg.cn[1];
9341 var contentCfg = cfg.cn[2];
9343 if(this.indicatorpos == 'right'){
9348 cls : 'control-label col-form-label',
9352 html : this.fieldLabel
9366 labelCfg = cfg.cn[0];
9367 contentCfg = cfg.cn[1];
9371 if(this.labelWidth > 12){
9372 labelCfg.style = "width: " + this.labelWidth + 'px';
9375 if(this.labelWidth < 13 && this.labelmd == 0){
9376 this.labelmd = this.labelWidth;
9379 if(this.labellg > 0){
9380 labelCfg.cls += ' col-lg-' + this.labellg;
9381 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9384 if(this.labelmd > 0){
9385 labelCfg.cls += ' col-md-' + this.labelmd;
9386 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9389 if(this.labelsm > 0){
9390 labelCfg.cls += ' col-sm-' + this.labelsm;
9391 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9394 if(this.labelxs > 0){
9395 labelCfg.cls += ' col-xs-' + this.labelxs;
9396 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9400 } else if ( this.fieldLabel.length) {
9405 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9406 tooltip : 'This field is required'
9410 //cls : 'input-group-addon',
9411 html : this.fieldLabel
9419 if(this.indicatorpos == 'right'){
9424 //cls : 'input-group-addon',
9425 html : this.fieldLabel
9430 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9431 tooltip : 'This field is required'
9451 if (this.parentType === 'Navbar' && this.parent().bar) {
9452 cfg.cls += ' navbar-form';
9455 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9456 // on BS4 we do this only if not form
9457 cfg.cls += ' navbar-form';
9465 * return the real input element.
9467 inputEl: function ()
9469 return this.el.select('input.form-control',true).first();
9472 tooltipEl : function()
9474 return this.inputEl();
9477 indicatorEl : function()
9479 if (Roo.bootstrap.version == 4) {
9480 return false; // not enabled in v4 yet.
9483 var indicator = this.el.select('i.roo-required-indicator',true).first();
9493 setDisabled : function(v)
9495 var i = this.inputEl().dom;
9497 i.removeAttribute('disabled');
9501 i.setAttribute('disabled','true');
9503 initEvents : function()
9506 this.inputEl().on("keydown" , this.fireKey, this);
9507 this.inputEl().on("focus", this.onFocus, this);
9508 this.inputEl().on("blur", this.onBlur, this);
9510 this.inputEl().relayEvent('keyup', this);
9512 this.indicator = this.indicatorEl();
9515 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9518 // reference to original value for reset
9519 this.originalValue = this.getValue();
9520 //Roo.form.TextField.superclass.initEvents.call(this);
9521 if(this.validationEvent == 'keyup'){
9522 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9523 this.inputEl().on('keyup', this.filterValidation, this);
9525 else if(this.validationEvent !== false){
9526 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9529 if(this.selectOnFocus){
9530 this.on("focus", this.preFocus, this);
9533 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9534 this.inputEl().on("keypress", this.filterKeys, this);
9536 this.inputEl().relayEvent('keypress', this);
9539 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9540 this.el.on("click", this.autoSize, this);
9543 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9544 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9547 if (typeof(this.before) == 'object') {
9548 this.before.render(this.el.select('.roo-input-before',true).first());
9550 if (typeof(this.after) == 'object') {
9551 this.after.render(this.el.select('.roo-input-after',true).first());
9554 this.inputEl().on('change', this.onChange, this);
9557 filterValidation : function(e){
9558 if(!e.isNavKeyPress()){
9559 this.validationTask.delay(this.validationDelay);
9563 * Validates the field value
9564 * @return {Boolean} True if the value is valid, else false
9566 validate : function(){
9567 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9568 if(this.disabled || this.validateValue(this.getRawValue())){
9579 * Validates a value according to the field's validation rules and marks the field as invalid
9580 * if the validation fails
9581 * @param {Mixed} value The value to validate
9582 * @return {Boolean} True if the value is valid, else false
9584 validateValue : function(value)
9586 if(this.getVisibilityEl().hasClass('hidden')){
9590 if(value.length < 1) { // if it's blank
9591 if(this.allowBlank){
9597 if(value.length < this.minLength){
9600 if(value.length > this.maxLength){
9604 var vt = Roo.form.VTypes;
9605 if(!vt[this.vtype](value, this)){
9609 if(typeof this.validator == "function"){
9610 var msg = this.validator(value);
9614 if (typeof(msg) == 'string') {
9615 this.invalidText = msg;
9619 if(this.regex && !this.regex.test(value)){
9627 fireKey : function(e){
9628 //Roo.log('field ' + e.getKey());
9629 if(e.isNavKeyPress()){
9630 this.fireEvent("specialkey", this, e);
9633 focus : function (selectText){
9635 this.inputEl().focus();
9636 if(selectText === true){
9637 this.inputEl().dom.select();
9643 onFocus : function(){
9644 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9645 // this.el.addClass(this.focusClass);
9648 this.hasFocus = true;
9649 this.startValue = this.getValue();
9650 this.fireEvent("focus", this);
9654 beforeBlur : Roo.emptyFn,
9658 onBlur : function(){
9660 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9661 //this.el.removeClass(this.focusClass);
9663 this.hasFocus = false;
9664 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9667 var v = this.getValue();
9668 if(String(v) !== String(this.startValue)){
9669 this.fireEvent('change', this, v, this.startValue);
9671 this.fireEvent("blur", this);
9674 onChange : function(e)
9676 var v = this.getValue();
9677 if(String(v) !== String(this.startValue)){
9678 this.fireEvent('change', this, v, this.startValue);
9684 * Resets the current field value to the originally loaded value and clears any validation messages
9687 this.setValue(this.originalValue);
9691 * Returns the name of the field
9692 * @return {Mixed} name The name field
9694 getName: function(){
9698 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9699 * @return {Mixed} value The field value
9701 getValue : function(){
9703 var v = this.inputEl().getValue();
9708 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9709 * @return {Mixed} value The field value
9711 getRawValue : function(){
9712 var v = this.inputEl().getValue();
9718 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9719 * @param {Mixed} value The value to set
9721 setRawValue : function(v){
9722 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9725 selectText : function(start, end){
9726 var v = this.getRawValue();
9728 start = start === undefined ? 0 : start;
9729 end = end === undefined ? v.length : end;
9730 var d = this.inputEl().dom;
9731 if(d.setSelectionRange){
9732 d.setSelectionRange(start, end);
9733 }else if(d.createTextRange){
9734 var range = d.createTextRange();
9735 range.moveStart("character", start);
9736 range.moveEnd("character", v.length-end);
9743 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9744 * @param {Mixed} value The value to set
9746 setValue : function(v){
9749 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9755 processValue : function(value){
9756 if(this.stripCharsRe){
9757 var newValue = value.replace(this.stripCharsRe, '');
9758 if(newValue !== value){
9759 this.setRawValue(newValue);
9766 preFocus : function(){
9768 if(this.selectOnFocus){
9769 this.inputEl().dom.select();
9772 filterKeys : function(e){
9774 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9777 var c = e.getCharCode(), cc = String.fromCharCode(c);
9778 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9781 if(!this.maskRe.test(cc)){
9786 * Clear any invalid styles/messages for this field
9788 clearInvalid : function(){
9790 if(!this.el || this.preventMark){ // not rendered
9795 this.el.removeClass([this.invalidClass, 'is-invalid']);
9797 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9799 var feedback = this.el.select('.form-control-feedback', true).first();
9802 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9808 this.indicator.removeClass('visible');
9809 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9812 this.fireEvent('valid', this);
9816 * Mark this field as valid
9818 markValid : function()
9820 if(!this.el || this.preventMark){ // not rendered...
9824 this.el.removeClass([this.invalidClass, this.validClass]);
9825 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9827 var feedback = this.el.select('.form-control-feedback', true).first();
9830 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9834 this.indicator.removeClass('visible');
9835 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9842 if(this.allowBlank && !this.getRawValue().length){
9845 if (Roo.bootstrap.version == 3) {
9846 this.el.addClass(this.validClass);
9848 this.inputEl().addClass('is-valid');
9851 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9853 var feedback = this.el.select('.form-control-feedback', true).first();
9856 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9857 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9862 this.fireEvent('valid', this);
9866 * Mark this field as invalid
9867 * @param {String} msg The validation message
9869 markInvalid : function(msg)
9871 if(!this.el || this.preventMark){ // not rendered
9875 this.el.removeClass([this.invalidClass, this.validClass]);
9876 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9878 var feedback = this.el.select('.form-control-feedback', true).first();
9881 this.el.select('.form-control-feedback', true).first().removeClass(
9882 [this.invalidFeedbackClass, this.validFeedbackClass]);
9889 if(this.allowBlank && !this.getRawValue().length){
9894 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9895 this.indicator.addClass('visible');
9897 if (Roo.bootstrap.version == 3) {
9898 this.el.addClass(this.invalidClass);
9900 this.inputEl().addClass('is-invalid');
9905 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9907 var feedback = this.el.select('.form-control-feedback', true).first();
9910 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9912 if(this.getValue().length || this.forceFeedback){
9913 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9920 this.fireEvent('invalid', this, msg);
9923 SafariOnKeyDown : function(event)
9925 // this is a workaround for a password hang bug on chrome/ webkit.
9926 if (this.inputEl().dom.type != 'password') {
9930 var isSelectAll = false;
9932 if(this.inputEl().dom.selectionEnd > 0){
9933 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9935 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9936 event.preventDefault();
9941 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9943 event.preventDefault();
9944 // this is very hacky as keydown always get's upper case.
9946 var cc = String.fromCharCode(event.getCharCode());
9947 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9951 adjustWidth : function(tag, w){
9952 tag = tag.toLowerCase();
9953 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9954 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9958 if(tag == 'textarea'){
9961 }else if(Roo.isOpera){
9965 if(tag == 'textarea'){
9973 setFieldLabel : function(v)
9979 if(this.indicatorEl()){
9980 var ar = this.el.select('label > span',true);
9982 if (ar.elements.length) {
9983 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9984 this.fieldLabel = v;
9988 var br = this.el.select('label',true);
9990 if(br.elements.length) {
9991 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9992 this.fieldLabel = v;
9996 Roo.log('Cannot Found any of label > span || label in input');
10000 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10001 this.fieldLabel = v;
10016 * @class Roo.bootstrap.TextArea
10017 * @extends Roo.bootstrap.Input
10018 * Bootstrap TextArea class
10019 * @cfg {Number} cols Specifies the visible width of a text area
10020 * @cfg {Number} rows Specifies the visible number of lines in a text area
10021 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10022 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10023 * @cfg {string} html text
10026 * Create a new TextArea
10027 * @param {Object} config The config object
10030 Roo.bootstrap.TextArea = function(config){
10031 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10035 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10045 getAutoCreate : function(){
10047 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10053 if(this.inputType != 'hidden'){
10054 cfg.cls = 'form-group' //input-group
10062 value : this.value || '',
10063 html: this.html || '',
10064 cls : 'form-control',
10065 placeholder : this.placeholder || ''
10069 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10070 input.maxLength = this.maxLength;
10074 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10078 input.cols = this.cols;
10081 if (this.readOnly) {
10082 input.readonly = true;
10086 input.name = this.name;
10090 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10094 ['xs','sm','md','lg'].map(function(size){
10095 if (settings[size]) {
10096 cfg.cls += ' col-' + size + '-' + settings[size];
10100 var inputblock = input;
10102 if(this.hasFeedback && !this.allowBlank){
10106 cls: 'glyphicon form-control-feedback'
10110 cls : 'has-feedback',
10119 if (this.before || this.after) {
10122 cls : 'input-group',
10126 inputblock.cn.push({
10128 cls : 'input-group-addon',
10133 inputblock.cn.push(input);
10135 if(this.hasFeedback && !this.allowBlank){
10136 inputblock.cls += ' has-feedback';
10137 inputblock.cn.push(feedback);
10141 inputblock.cn.push({
10143 cls : 'input-group-addon',
10150 if (align ==='left' && this.fieldLabel.length) {
10155 cls : 'control-label',
10156 html : this.fieldLabel
10167 if(this.labelWidth > 12){
10168 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10171 if(this.labelWidth < 13 && this.labelmd == 0){
10172 this.labelmd = this.labelWidth;
10175 if(this.labellg > 0){
10176 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10177 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10180 if(this.labelmd > 0){
10181 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10182 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10185 if(this.labelsm > 0){
10186 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10187 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10190 if(this.labelxs > 0){
10191 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10192 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10195 } else if ( this.fieldLabel.length) {
10200 //cls : 'input-group-addon',
10201 html : this.fieldLabel
10219 if (this.disabled) {
10220 input.disabled=true;
10227 * return the real textarea element.
10229 inputEl: function ()
10231 return this.el.select('textarea.form-control',true).first();
10235 * Clear any invalid styles/messages for this field
10237 clearInvalid : function()
10240 if(!this.el || this.preventMark){ // not rendered
10244 var label = this.el.select('label', true).first();
10245 var icon = this.el.select('i.fa-star', true).first();
10250 this.el.removeClass( this.validClass);
10251 this.inputEl().removeClass('is-invalid');
10253 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10255 var feedback = this.el.select('.form-control-feedback', true).first();
10258 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10263 this.fireEvent('valid', this);
10267 * Mark this field as valid
10269 markValid : function()
10271 if(!this.el || this.preventMark){ // not rendered
10275 this.el.removeClass([this.invalidClass, this.validClass]);
10276 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10278 var feedback = this.el.select('.form-control-feedback', true).first();
10281 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10284 if(this.disabled || this.allowBlank){
10288 var label = this.el.select('label', true).first();
10289 var icon = this.el.select('i.fa-star', true).first();
10294 if (Roo.bootstrap.version == 3) {
10295 this.el.addClass(this.validClass);
10297 this.inputEl().addClass('is-valid');
10301 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10303 var feedback = this.el.select('.form-control-feedback', true).first();
10306 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10307 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10312 this.fireEvent('valid', this);
10316 * Mark this field as invalid
10317 * @param {String} msg The validation message
10319 markInvalid : function(msg)
10321 if(!this.el || this.preventMark){ // not rendered
10325 this.el.removeClass([this.invalidClass, this.validClass]);
10326 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10328 var feedback = this.el.select('.form-control-feedback', true).first();
10331 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10334 if(this.disabled || this.allowBlank){
10338 var label = this.el.select('label', true).first();
10339 var icon = this.el.select('i.fa-star', true).first();
10341 if(!this.getValue().length && label && !icon){
10342 this.el.createChild({
10344 cls : 'text-danger fa fa-lg fa-star',
10345 tooltip : 'This field is required',
10346 style : 'margin-right:5px;'
10350 if (Roo.bootstrap.version == 3) {
10351 this.el.addClass(this.invalidClass);
10353 this.inputEl().addClass('is-invalid');
10356 // fixme ... this may be depricated need to test..
10357 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10359 var feedback = this.el.select('.form-control-feedback', true).first();
10362 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10364 if(this.getValue().length || this.forceFeedback){
10365 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10372 this.fireEvent('invalid', this, msg);
10380 * trigger field - base class for combo..
10385 * @class Roo.bootstrap.TriggerField
10386 * @extends Roo.bootstrap.Input
10387 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10388 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10389 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10390 * for which you can provide a custom implementation. For example:
10392 var trigger = new Roo.bootstrap.TriggerField();
10393 trigger.onTriggerClick = myTriggerFn;
10394 trigger.applyTo('my-field');
10397 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10398 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10399 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10400 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10401 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10404 * Create a new TriggerField.
10405 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10406 * to the base TextField)
10408 Roo.bootstrap.TriggerField = function(config){
10409 this.mimicing = false;
10410 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10413 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10415 * @cfg {String} triggerClass A CSS class to apply to the trigger
10418 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10423 * @cfg {Boolean} removable (true|false) special filter default false
10427 /** @cfg {Boolean} grow @hide */
10428 /** @cfg {Number} growMin @hide */
10429 /** @cfg {Number} growMax @hide */
10435 autoSize: Roo.emptyFn,
10439 deferHeight : true,
10442 actionMode : 'wrap',
10447 getAutoCreate : function(){
10449 var align = this.labelAlign || this.parentLabelAlign();
10454 cls: 'form-group' //input-group
10461 type : this.inputType,
10462 cls : 'form-control',
10463 autocomplete: 'new-password',
10464 placeholder : this.placeholder || ''
10468 input.name = this.name;
10471 input.cls += ' input-' + this.size;
10474 if (this.disabled) {
10475 input.disabled=true;
10478 var inputblock = input;
10480 if(this.hasFeedback && !this.allowBlank){
10484 cls: 'glyphicon form-control-feedback'
10487 if(this.removable && !this.editable && !this.tickable){
10489 cls : 'has-feedback',
10495 cls : 'roo-combo-removable-btn close'
10502 cls : 'has-feedback',
10511 if(this.removable && !this.editable && !this.tickable){
10513 cls : 'roo-removable',
10519 cls : 'roo-combo-removable-btn close'
10526 if (this.before || this.after) {
10529 cls : 'input-group',
10533 inputblock.cn.push({
10535 cls : 'input-group-addon input-group-prepend input-group-text',
10540 inputblock.cn.push(input);
10542 if(this.hasFeedback && !this.allowBlank){
10543 inputblock.cls += ' has-feedback';
10544 inputblock.cn.push(feedback);
10548 inputblock.cn.push({
10550 cls : 'input-group-addon input-group-append input-group-text',
10559 var ibwrap = inputblock;
10564 cls: 'roo-select2-choices',
10568 cls: 'roo-select2-search-field',
10580 cls: 'roo-select2-container input-group',
10585 cls: 'form-hidden-field'
10591 if(!this.multiple && this.showToggleBtn){
10597 if (this.caret != false) {
10600 cls: 'fa fa-' + this.caret
10607 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10612 cls: 'combobox-clear',
10626 combobox.cls += ' roo-select2-container-multi';
10630 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10631 tooltip : 'This field is required'
10633 if (Roo.bootstrap.version == 4) {
10636 style : 'display:none'
10641 if (align ==='left' && this.fieldLabel.length) {
10643 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10650 cls : 'control-label',
10651 html : this.fieldLabel
10663 var labelCfg = cfg.cn[1];
10664 var contentCfg = cfg.cn[2];
10666 if(this.indicatorpos == 'right'){
10671 cls : 'control-label',
10675 html : this.fieldLabel
10689 labelCfg = cfg.cn[0];
10690 contentCfg = cfg.cn[1];
10693 if(this.labelWidth > 12){
10694 labelCfg.style = "width: " + this.labelWidth + 'px';
10697 if(this.labelWidth < 13 && this.labelmd == 0){
10698 this.labelmd = this.labelWidth;
10701 if(this.labellg > 0){
10702 labelCfg.cls += ' col-lg-' + this.labellg;
10703 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10706 if(this.labelmd > 0){
10707 labelCfg.cls += ' col-md-' + this.labelmd;
10708 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10711 if(this.labelsm > 0){
10712 labelCfg.cls += ' col-sm-' + this.labelsm;
10713 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10716 if(this.labelxs > 0){
10717 labelCfg.cls += ' col-xs-' + this.labelxs;
10718 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10721 } else if ( this.fieldLabel.length) {
10722 // Roo.log(" label");
10727 //cls : 'input-group-addon',
10728 html : this.fieldLabel
10736 if(this.indicatorpos == 'right'){
10744 html : this.fieldLabel
10758 // Roo.log(" no label && no align");
10765 ['xs','sm','md','lg'].map(function(size){
10766 if (settings[size]) {
10767 cfg.cls += ' col-' + size + '-' + settings[size];
10778 onResize : function(w, h){
10779 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10780 // if(typeof w == 'number'){
10781 // var x = w - this.trigger.getWidth();
10782 // this.inputEl().setWidth(this.adjustWidth('input', x));
10783 // this.trigger.setStyle('left', x+'px');
10788 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10791 getResizeEl : function(){
10792 return this.inputEl();
10796 getPositionEl : function(){
10797 return this.inputEl();
10801 alignErrorIcon : function(){
10802 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10806 initEvents : function(){
10810 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10811 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10812 if(!this.multiple && this.showToggleBtn){
10813 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10814 if(this.hideTrigger){
10815 this.trigger.setDisplayed(false);
10817 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10821 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10824 if(this.removable && !this.editable && !this.tickable){
10825 var close = this.closeTriggerEl();
10828 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10829 close.on('click', this.removeBtnClick, this, close);
10833 //this.trigger.addClassOnOver('x-form-trigger-over');
10834 //this.trigger.addClassOnClick('x-form-trigger-click');
10837 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10841 closeTriggerEl : function()
10843 var close = this.el.select('.roo-combo-removable-btn', true).first();
10844 return close ? close : false;
10847 removeBtnClick : function(e, h, el)
10849 e.preventDefault();
10851 if(this.fireEvent("remove", this) !== false){
10853 this.fireEvent("afterremove", this)
10857 createList : function()
10859 this.list = Roo.get(document.body).createChild({
10860 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10861 cls: 'typeahead typeahead-long dropdown-menu',
10862 style: 'display:none'
10865 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10870 initTrigger : function(){
10875 onDestroy : function(){
10877 this.trigger.removeAllListeners();
10878 // this.trigger.remove();
10881 // this.wrap.remove();
10883 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10887 onFocus : function(){
10888 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10890 if(!this.mimicing){
10891 this.wrap.addClass('x-trigger-wrap-focus');
10892 this.mimicing = true;
10893 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10894 if(this.monitorTab){
10895 this.el.on("keydown", this.checkTab, this);
10902 checkTab : function(e){
10903 if(e.getKey() == e.TAB){
10904 this.triggerBlur();
10909 onBlur : function(){
10914 mimicBlur : function(e, t){
10916 if(!this.wrap.contains(t) && this.validateBlur()){
10917 this.triggerBlur();
10923 triggerBlur : function(){
10924 this.mimicing = false;
10925 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10926 if(this.monitorTab){
10927 this.el.un("keydown", this.checkTab, this);
10929 //this.wrap.removeClass('x-trigger-wrap-focus');
10930 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10934 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10935 validateBlur : function(e, t){
10940 onDisable : function(){
10941 this.inputEl().dom.disabled = true;
10942 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10944 // this.wrap.addClass('x-item-disabled');
10949 onEnable : function(){
10950 this.inputEl().dom.disabled = false;
10951 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10953 // this.el.removeClass('x-item-disabled');
10958 onShow : function(){
10959 var ae = this.getActionEl();
10962 ae.dom.style.display = '';
10963 ae.dom.style.visibility = 'visible';
10969 onHide : function(){
10970 var ae = this.getActionEl();
10971 ae.dom.style.display = 'none';
10975 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10976 * by an implementing function.
10978 * @param {EventObject} e
10980 onTriggerClick : Roo.emptyFn
10984 * Ext JS Library 1.1.1
10985 * Copyright(c) 2006-2007, Ext JS, LLC.
10987 * Originally Released Under LGPL - original licence link has changed is not relivant.
10990 * <script type="text/javascript">
10995 * @class Roo.data.SortTypes
10997 * Defines the default sorting (casting?) comparison functions used when sorting data.
10999 Roo.data.SortTypes = {
11001 * Default sort that does nothing
11002 * @param {Mixed} s The value being converted
11003 * @return {Mixed} The comparison value
11005 none : function(s){
11010 * The regular expression used to strip tags
11014 stripTagsRE : /<\/?[^>]+>/gi,
11017 * Strips all HTML tags to sort on text only
11018 * @param {Mixed} s The value being converted
11019 * @return {String} The comparison value
11021 asText : function(s){
11022 return String(s).replace(this.stripTagsRE, "");
11026 * Strips all HTML tags to sort on text only - Case insensitive
11027 * @param {Mixed} s The value being converted
11028 * @return {String} The comparison value
11030 asUCText : function(s){
11031 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11035 * Case insensitive string
11036 * @param {Mixed} s The value being converted
11037 * @return {String} The comparison value
11039 asUCString : function(s) {
11040 return String(s).toUpperCase();
11045 * @param {Mixed} s The value being converted
11046 * @return {Number} The comparison value
11048 asDate : function(s) {
11052 if(s instanceof Date){
11053 return s.getTime();
11055 return Date.parse(String(s));
11060 * @param {Mixed} s The value being converted
11061 * @return {Float} The comparison value
11063 asFloat : function(s) {
11064 var val = parseFloat(String(s).replace(/,/g, ""));
11073 * @param {Mixed} s The value being converted
11074 * @return {Number} The comparison value
11076 asInt : function(s) {
11077 var val = parseInt(String(s).replace(/,/g, ""));
11085 * Ext JS Library 1.1.1
11086 * Copyright(c) 2006-2007, Ext JS, LLC.
11088 * Originally Released Under LGPL - original licence link has changed is not relivant.
11091 * <script type="text/javascript">
11095 * @class Roo.data.Record
11096 * Instances of this class encapsulate both record <em>definition</em> information, and record
11097 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11098 * to access Records cached in an {@link Roo.data.Store} object.<br>
11100 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11101 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11104 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11106 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11107 * {@link #create}. The parameters are the same.
11108 * @param {Array} data An associative Array of data values keyed by the field name.
11109 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11110 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11111 * not specified an integer id is generated.
11113 Roo.data.Record = function(data, id){
11114 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11119 * Generate a constructor for a specific record layout.
11120 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11121 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11122 * Each field definition object may contain the following properties: <ul>
11123 * <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,
11124 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11125 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11126 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11127 * is being used, then this is a string containing the javascript expression to reference the data relative to
11128 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11129 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11130 * this may be omitted.</p></li>
11131 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11132 * <ul><li>auto (Default, implies no conversion)</li>
11137 * <li>date</li></ul></p></li>
11138 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11139 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11140 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11141 * by the Reader into an object that will be stored in the Record. It is passed the
11142 * following parameters:<ul>
11143 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11145 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11147 * <br>usage:<br><pre><code>
11148 var TopicRecord = Roo.data.Record.create(
11149 {name: 'title', mapping: 'topic_title'},
11150 {name: 'author', mapping: 'username'},
11151 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11152 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11153 {name: 'lastPoster', mapping: 'user2'},
11154 {name: 'excerpt', mapping: 'post_text'}
11157 var myNewRecord = new TopicRecord({
11158 title: 'Do my job please',
11161 lastPost: new Date(),
11162 lastPoster: 'Animal',
11163 excerpt: 'No way dude!'
11165 myStore.add(myNewRecord);
11170 Roo.data.Record.create = function(o){
11171 var f = function(){
11172 f.superclass.constructor.apply(this, arguments);
11174 Roo.extend(f, Roo.data.Record);
11175 var p = f.prototype;
11176 p.fields = new Roo.util.MixedCollection(false, function(field){
11179 for(var i = 0, len = o.length; i < len; i++){
11180 p.fields.add(new Roo.data.Field(o[i]));
11182 f.getField = function(name){
11183 return p.fields.get(name);
11188 Roo.data.Record.AUTO_ID = 1000;
11189 Roo.data.Record.EDIT = 'edit';
11190 Roo.data.Record.REJECT = 'reject';
11191 Roo.data.Record.COMMIT = 'commit';
11193 Roo.data.Record.prototype = {
11195 * Readonly flag - true if this record has been modified.
11204 join : function(store){
11205 this.store = store;
11209 * Set the named field to the specified value.
11210 * @param {String} name The name of the field to set.
11211 * @param {Object} value The value to set the field to.
11213 set : function(name, value){
11214 if(this.data[name] == value){
11218 if(!this.modified){
11219 this.modified = {};
11221 if(typeof this.modified[name] == 'undefined'){
11222 this.modified[name] = this.data[name];
11224 this.data[name] = value;
11225 if(!this.editing && this.store){
11226 this.store.afterEdit(this);
11231 * Get the value of the named field.
11232 * @param {String} name The name of the field to get the value of.
11233 * @return {Object} The value of the field.
11235 get : function(name){
11236 return this.data[name];
11240 beginEdit : function(){
11241 this.editing = true;
11242 this.modified = {};
11246 cancelEdit : function(){
11247 this.editing = false;
11248 delete this.modified;
11252 endEdit : function(){
11253 this.editing = false;
11254 if(this.dirty && this.store){
11255 this.store.afterEdit(this);
11260 * Usually called by the {@link Roo.data.Store} which owns the Record.
11261 * Rejects all changes made to the Record since either creation, or the last commit operation.
11262 * Modified fields are reverted to their original values.
11264 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11265 * of reject operations.
11267 reject : function(){
11268 var m = this.modified;
11270 if(typeof m[n] != "function"){
11271 this.data[n] = m[n];
11274 this.dirty = false;
11275 delete this.modified;
11276 this.editing = false;
11278 this.store.afterReject(this);
11283 * Usually called by the {@link Roo.data.Store} which owns the Record.
11284 * Commits all changes made to the Record since either creation, or the last commit operation.
11286 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11287 * of commit operations.
11289 commit : function(){
11290 this.dirty = false;
11291 delete this.modified;
11292 this.editing = false;
11294 this.store.afterCommit(this);
11299 hasError : function(){
11300 return this.error != null;
11304 clearError : function(){
11309 * Creates a copy of this record.
11310 * @param {String} id (optional) A new record id if you don't want to use this record's id
11313 copy : function(newId) {
11314 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11318 * Ext JS Library 1.1.1
11319 * Copyright(c) 2006-2007, Ext JS, LLC.
11321 * Originally Released Under LGPL - original licence link has changed is not relivant.
11324 * <script type="text/javascript">
11330 * @class Roo.data.Store
11331 * @extends Roo.util.Observable
11332 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11333 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11335 * 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
11336 * has no knowledge of the format of the data returned by the Proxy.<br>
11338 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11339 * instances from the data object. These records are cached and made available through accessor functions.
11341 * Creates a new Store.
11342 * @param {Object} config A config object containing the objects needed for the Store to access data,
11343 * and read the data into Records.
11345 Roo.data.Store = function(config){
11346 this.data = new Roo.util.MixedCollection(false);
11347 this.data.getKey = function(o){
11350 this.baseParams = {};
11352 this.paramNames = {
11357 "multisort" : "_multisort"
11360 if(config && config.data){
11361 this.inlineData = config.data;
11362 delete config.data;
11365 Roo.apply(this, config);
11367 if(this.reader){ // reader passed
11368 this.reader = Roo.factory(this.reader, Roo.data);
11369 this.reader.xmodule = this.xmodule || false;
11370 if(!this.recordType){
11371 this.recordType = this.reader.recordType;
11373 if(this.reader.onMetaChange){
11374 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11378 if(this.recordType){
11379 this.fields = this.recordType.prototype.fields;
11381 this.modified = [];
11385 * @event datachanged
11386 * Fires when the data cache has changed, and a widget which is using this Store
11387 * as a Record cache should refresh its view.
11388 * @param {Store} this
11390 datachanged : true,
11392 * @event metachange
11393 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11394 * @param {Store} this
11395 * @param {Object} meta The JSON metadata
11400 * Fires when Records have been added to the Store
11401 * @param {Store} this
11402 * @param {Roo.data.Record[]} records The array of Records added
11403 * @param {Number} index The index at which the record(s) were added
11408 * Fires when a Record has been removed from the Store
11409 * @param {Store} this
11410 * @param {Roo.data.Record} record The Record that was removed
11411 * @param {Number} index The index at which the record was removed
11416 * Fires when a Record has been updated
11417 * @param {Store} this
11418 * @param {Roo.data.Record} record The Record that was updated
11419 * @param {String} operation The update operation being performed. Value may be one of:
11421 Roo.data.Record.EDIT
11422 Roo.data.Record.REJECT
11423 Roo.data.Record.COMMIT
11429 * Fires when the data cache has been cleared.
11430 * @param {Store} this
11434 * @event beforeload
11435 * Fires before a request is made for a new data object. If the beforeload handler returns false
11436 * the load action will be canceled.
11437 * @param {Store} this
11438 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11442 * @event beforeloadadd
11443 * Fires after a new set of Records has been loaded.
11444 * @param {Store} this
11445 * @param {Roo.data.Record[]} records The Records that were loaded
11446 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11448 beforeloadadd : true,
11451 * Fires after a new set of Records has been loaded, before they are added to the store.
11452 * @param {Store} this
11453 * @param {Roo.data.Record[]} records The Records that were loaded
11454 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11455 * @params {Object} return from reader
11459 * @event loadexception
11460 * Fires if an exception occurs in the Proxy during loading.
11461 * Called with the signature of the Proxy's "loadexception" event.
11462 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11465 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11466 * @param {Object} load options
11467 * @param {Object} jsonData from your request (normally this contains the Exception)
11469 loadexception : true
11473 this.proxy = Roo.factory(this.proxy, Roo.data);
11474 this.proxy.xmodule = this.xmodule || false;
11475 this.relayEvents(this.proxy, ["loadexception"]);
11477 this.sortToggle = {};
11478 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11480 Roo.data.Store.superclass.constructor.call(this);
11482 if(this.inlineData){
11483 this.loadData(this.inlineData);
11484 delete this.inlineData;
11488 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11490 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11491 * without a remote query - used by combo/forms at present.
11495 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11498 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11501 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11502 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11505 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11506 * on any HTTP request
11509 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11512 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11516 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11517 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11519 remoteSort : false,
11522 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11523 * loaded or when a record is removed. (defaults to false).
11525 pruneModifiedRecords : false,
11528 lastOptions : null,
11531 * Add Records to the Store and fires the add event.
11532 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11534 add : function(records){
11535 records = [].concat(records);
11536 for(var i = 0, len = records.length; i < len; i++){
11537 records[i].join(this);
11539 var index = this.data.length;
11540 this.data.addAll(records);
11541 this.fireEvent("add", this, records, index);
11545 * Remove a Record from the Store and fires the remove event.
11546 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11548 remove : function(record){
11549 var index = this.data.indexOf(record);
11550 this.data.removeAt(index);
11552 if(this.pruneModifiedRecords){
11553 this.modified.remove(record);
11555 this.fireEvent("remove", this, record, index);
11559 * Remove all Records from the Store and fires the clear event.
11561 removeAll : function(){
11563 if(this.pruneModifiedRecords){
11564 this.modified = [];
11566 this.fireEvent("clear", this);
11570 * Inserts Records to the Store at the given index and fires the add event.
11571 * @param {Number} index The start index at which to insert the passed Records.
11572 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11574 insert : function(index, records){
11575 records = [].concat(records);
11576 for(var i = 0, len = records.length; i < len; i++){
11577 this.data.insert(index, records[i]);
11578 records[i].join(this);
11580 this.fireEvent("add", this, records, index);
11584 * Get the index within the cache of the passed Record.
11585 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11586 * @return {Number} The index of the passed Record. Returns -1 if not found.
11588 indexOf : function(record){
11589 return this.data.indexOf(record);
11593 * Get the index within the cache of the Record with the passed id.
11594 * @param {String} id The id of the Record to find.
11595 * @return {Number} The index of the Record. Returns -1 if not found.
11597 indexOfId : function(id){
11598 return this.data.indexOfKey(id);
11602 * Get the Record with the specified id.
11603 * @param {String} id The id of the Record to find.
11604 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11606 getById : function(id){
11607 return this.data.key(id);
11611 * Get the Record at the specified index.
11612 * @param {Number} index The index of the Record to find.
11613 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11615 getAt : function(index){
11616 return this.data.itemAt(index);
11620 * Returns a range of Records between specified indices.
11621 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11622 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11623 * @return {Roo.data.Record[]} An array of Records
11625 getRange : function(start, end){
11626 return this.data.getRange(start, end);
11630 storeOptions : function(o){
11631 o = Roo.apply({}, o);
11634 this.lastOptions = o;
11638 * Loads the Record cache from the configured Proxy using the configured Reader.
11640 * If using remote paging, then the first load call must specify the <em>start</em>
11641 * and <em>limit</em> properties in the options.params property to establish the initial
11642 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11644 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11645 * and this call will return before the new data has been loaded. Perform any post-processing
11646 * in a callback function, or in a "load" event handler.</strong>
11648 * @param {Object} options An object containing properties which control loading options:<ul>
11649 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11650 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11651 * passed the following arguments:<ul>
11652 * <li>r : Roo.data.Record[]</li>
11653 * <li>options: Options object from the load call</li>
11654 * <li>success: Boolean success indicator</li></ul></li>
11655 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11656 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11659 load : function(options){
11660 options = options || {};
11661 if(this.fireEvent("beforeload", this, options) !== false){
11662 this.storeOptions(options);
11663 var p = Roo.apply(options.params || {}, this.baseParams);
11664 // if meta was not loaded from remote source.. try requesting it.
11665 if (!this.reader.metaFromRemote) {
11666 p._requestMeta = 1;
11668 if(this.sortInfo && this.remoteSort){
11669 var pn = this.paramNames;
11670 p[pn["sort"]] = this.sortInfo.field;
11671 p[pn["dir"]] = this.sortInfo.direction;
11673 if (this.multiSort) {
11674 var pn = this.paramNames;
11675 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11678 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11683 * Reloads the Record cache from the configured Proxy using the configured Reader and
11684 * the options from the last load operation performed.
11685 * @param {Object} options (optional) An object containing properties which may override the options
11686 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11687 * the most recently used options are reused).
11689 reload : function(options){
11690 this.load(Roo.applyIf(options||{}, this.lastOptions));
11694 // Called as a callback by the Reader during a load operation.
11695 loadRecords : function(o, options, success){
11696 if(!o || success === false){
11697 if(success !== false){
11698 this.fireEvent("load", this, [], options, o);
11700 if(options.callback){
11701 options.callback.call(options.scope || this, [], options, false);
11705 // if data returned failure - throw an exception.
11706 if (o.success === false) {
11707 // show a message if no listener is registered.
11708 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11709 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11711 // loadmask wil be hooked into this..
11712 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11715 var r = o.records, t = o.totalRecords || r.length;
11717 this.fireEvent("beforeloadadd", this, r, options, o);
11719 if(!options || options.add !== true){
11720 if(this.pruneModifiedRecords){
11721 this.modified = [];
11723 for(var i = 0, len = r.length; i < len; i++){
11727 this.data = this.snapshot;
11728 delete this.snapshot;
11731 this.data.addAll(r);
11732 this.totalLength = t;
11734 this.fireEvent("datachanged", this);
11736 this.totalLength = Math.max(t, this.data.length+r.length);
11740 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11742 var e = new Roo.data.Record({});
11744 e.set(this.parent.displayField, this.parent.emptyTitle);
11745 e.set(this.parent.valueField, '');
11750 this.fireEvent("load", this, r, options, o);
11751 if(options.callback){
11752 options.callback.call(options.scope || this, r, options, true);
11758 * Loads data from a passed data block. A Reader which understands the format of the data
11759 * must have been configured in the constructor.
11760 * @param {Object} data The data block from which to read the Records. The format of the data expected
11761 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11762 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11764 loadData : function(o, append){
11765 var r = this.reader.readRecords(o);
11766 this.loadRecords(r, {add: append}, true);
11770 * Gets the number of cached records.
11772 * <em>If using paging, this may not be the total size of the dataset. If the data object
11773 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11774 * the data set size</em>
11776 getCount : function(){
11777 return this.data.length || 0;
11781 * Gets the total number of records in the dataset as returned by the server.
11783 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11784 * the dataset size</em>
11786 getTotalCount : function(){
11787 return this.totalLength || 0;
11791 * Returns the sort state of the Store as an object with two properties:
11793 field {String} The name of the field by which the Records are sorted
11794 direction {String} The sort order, "ASC" or "DESC"
11797 getSortState : function(){
11798 return this.sortInfo;
11802 applySort : function(){
11803 if(this.sortInfo && !this.remoteSort){
11804 var s = this.sortInfo, f = s.field;
11805 var st = this.fields.get(f).sortType;
11806 var fn = function(r1, r2){
11807 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11808 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11810 this.data.sort(s.direction, fn);
11811 if(this.snapshot && this.snapshot != this.data){
11812 this.snapshot.sort(s.direction, fn);
11818 * Sets the default sort column and order to be used by the next load operation.
11819 * @param {String} fieldName The name of the field to sort by.
11820 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11822 setDefaultSort : function(field, dir){
11823 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11827 * Sort the Records.
11828 * If remote sorting is used, the sort is performed on the server, and the cache is
11829 * reloaded. If local sorting is used, the cache is sorted internally.
11830 * @param {String} fieldName The name of the field to sort by.
11831 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11833 sort : function(fieldName, dir){
11834 var f = this.fields.get(fieldName);
11836 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11838 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11839 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11844 this.sortToggle[f.name] = dir;
11845 this.sortInfo = {field: f.name, direction: dir};
11846 if(!this.remoteSort){
11848 this.fireEvent("datachanged", this);
11850 this.load(this.lastOptions);
11855 * Calls the specified function for each of the Records in the cache.
11856 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11857 * Returning <em>false</em> aborts and exits the iteration.
11858 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11860 each : function(fn, scope){
11861 this.data.each(fn, scope);
11865 * Gets all records modified since the last commit. Modified records are persisted across load operations
11866 * (e.g., during paging).
11867 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11869 getModifiedRecords : function(){
11870 return this.modified;
11874 createFilterFn : function(property, value, anyMatch){
11875 if(!value.exec){ // not a regex
11876 value = String(value);
11877 if(value.length == 0){
11880 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11882 return function(r){
11883 return value.test(r.data[property]);
11888 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11889 * @param {String} property A field on your records
11890 * @param {Number} start The record index to start at (defaults to 0)
11891 * @param {Number} end The last record index to include (defaults to length - 1)
11892 * @return {Number} The sum
11894 sum : function(property, start, end){
11895 var rs = this.data.items, v = 0;
11896 start = start || 0;
11897 end = (end || end === 0) ? end : rs.length-1;
11899 for(var i = start; i <= end; i++){
11900 v += (rs[i].data[property] || 0);
11906 * Filter the records by a specified property.
11907 * @param {String} field A field on your records
11908 * @param {String/RegExp} value Either a string that the field
11909 * should start with or a RegExp to test against the field
11910 * @param {Boolean} anyMatch True to match any part not just the beginning
11912 filter : function(property, value, anyMatch){
11913 var fn = this.createFilterFn(property, value, anyMatch);
11914 return fn ? this.filterBy(fn) : this.clearFilter();
11918 * Filter by a function. The specified function will be called with each
11919 * record in this data source. If the function returns true the record is included,
11920 * otherwise it is filtered.
11921 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11922 * @param {Object} scope (optional) The scope of the function (defaults to this)
11924 filterBy : function(fn, scope){
11925 this.snapshot = this.snapshot || this.data;
11926 this.data = this.queryBy(fn, scope||this);
11927 this.fireEvent("datachanged", this);
11931 * Query the records by a specified property.
11932 * @param {String} field A field on your records
11933 * @param {String/RegExp} value Either a string that the field
11934 * should start with or a RegExp to test against the field
11935 * @param {Boolean} anyMatch True to match any part not just the beginning
11936 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11938 query : function(property, value, anyMatch){
11939 var fn = this.createFilterFn(property, value, anyMatch);
11940 return fn ? this.queryBy(fn) : this.data.clone();
11944 * Query by a function. The specified function will be called with each
11945 * record in this data source. If the function returns true the record is included
11947 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11948 * @param {Object} scope (optional) The scope of the function (defaults to this)
11949 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11951 queryBy : function(fn, scope){
11952 var data = this.snapshot || this.data;
11953 return data.filterBy(fn, scope||this);
11957 * Collects unique values for a particular dataIndex from this store.
11958 * @param {String} dataIndex The property to collect
11959 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11960 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11961 * @return {Array} An array of the unique values
11963 collect : function(dataIndex, allowNull, bypassFilter){
11964 var d = (bypassFilter === true && this.snapshot) ?
11965 this.snapshot.items : this.data.items;
11966 var v, sv, r = [], l = {};
11967 for(var i = 0, len = d.length; i < len; i++){
11968 v = d[i].data[dataIndex];
11970 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11979 * Revert to a view of the Record cache with no filtering applied.
11980 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11982 clearFilter : function(suppressEvent){
11983 if(this.snapshot && this.snapshot != this.data){
11984 this.data = this.snapshot;
11985 delete this.snapshot;
11986 if(suppressEvent !== true){
11987 this.fireEvent("datachanged", this);
11993 afterEdit : function(record){
11994 if(this.modified.indexOf(record) == -1){
11995 this.modified.push(record);
11997 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12001 afterReject : function(record){
12002 this.modified.remove(record);
12003 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12007 afterCommit : function(record){
12008 this.modified.remove(record);
12009 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12013 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12014 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12016 commitChanges : function(){
12017 var m = this.modified.slice(0);
12018 this.modified = [];
12019 for(var i = 0, len = m.length; i < len; i++){
12025 * Cancel outstanding changes on all changed records.
12027 rejectChanges : function(){
12028 var m = this.modified.slice(0);
12029 this.modified = [];
12030 for(var i = 0, len = m.length; i < len; i++){
12035 onMetaChange : function(meta, rtype, o){
12036 this.recordType = rtype;
12037 this.fields = rtype.prototype.fields;
12038 delete this.snapshot;
12039 this.sortInfo = meta.sortInfo || this.sortInfo;
12040 this.modified = [];
12041 this.fireEvent('metachange', this, this.reader.meta);
12044 moveIndex : function(data, type)
12046 var index = this.indexOf(data);
12048 var newIndex = index + type;
12052 this.insert(newIndex, data);
12057 * Ext JS Library 1.1.1
12058 * Copyright(c) 2006-2007, Ext JS, LLC.
12060 * Originally Released Under LGPL - original licence link has changed is not relivant.
12063 * <script type="text/javascript">
12067 * @class Roo.data.SimpleStore
12068 * @extends Roo.data.Store
12069 * Small helper class to make creating Stores from Array data easier.
12070 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12071 * @cfg {Array} fields An array of field definition objects, or field name strings.
12072 * @cfg {Array} data The multi-dimensional array of data
12074 * @param {Object} config
12076 Roo.data.SimpleStore = function(config){
12077 Roo.data.SimpleStore.superclass.constructor.call(this, {
12079 reader: new Roo.data.ArrayReader({
12082 Roo.data.Record.create(config.fields)
12084 proxy : new Roo.data.MemoryProxy(config.data)
12088 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12090 * Ext JS Library 1.1.1
12091 * Copyright(c) 2006-2007, Ext JS, LLC.
12093 * Originally Released Under LGPL - original licence link has changed is not relivant.
12096 * <script type="text/javascript">
12101 * @extends Roo.data.Store
12102 * @class Roo.data.JsonStore
12103 * Small helper class to make creating Stores for JSON data easier. <br/>
12105 var store = new Roo.data.JsonStore({
12106 url: 'get-images.php',
12108 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12111 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12112 * JsonReader and HttpProxy (unless inline data is provided).</b>
12113 * @cfg {Array} fields An array of field definition objects, or field name strings.
12115 * @param {Object} config
12117 Roo.data.JsonStore = function(c){
12118 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12119 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12120 reader: new Roo.data.JsonReader(c, c.fields)
12123 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12125 * Ext JS Library 1.1.1
12126 * Copyright(c) 2006-2007, Ext JS, LLC.
12128 * Originally Released Under LGPL - original licence link has changed is not relivant.
12131 * <script type="text/javascript">
12135 Roo.data.Field = function(config){
12136 if(typeof config == "string"){
12137 config = {name: config};
12139 Roo.apply(this, config);
12142 this.type = "auto";
12145 var st = Roo.data.SortTypes;
12146 // named sortTypes are supported, here we look them up
12147 if(typeof this.sortType == "string"){
12148 this.sortType = st[this.sortType];
12151 // set default sortType for strings and dates
12152 if(!this.sortType){
12155 this.sortType = st.asUCString;
12158 this.sortType = st.asDate;
12161 this.sortType = st.none;
12166 var stripRe = /[\$,%]/g;
12168 // prebuilt conversion function for this field, instead of
12169 // switching every time we're reading a value
12171 var cv, dateFormat = this.dateFormat;
12176 cv = function(v){ return v; };
12179 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12183 return v !== undefined && v !== null && v !== '' ?
12184 parseInt(String(v).replace(stripRe, ""), 10) : '';
12189 return v !== undefined && v !== null && v !== '' ?
12190 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12195 cv = function(v){ return v === true || v === "true" || v == 1; };
12202 if(v instanceof Date){
12206 if(dateFormat == "timestamp"){
12207 return new Date(v*1000);
12209 return Date.parseDate(v, dateFormat);
12211 var parsed = Date.parse(v);
12212 return parsed ? new Date(parsed) : null;
12221 Roo.data.Field.prototype = {
12229 * Ext JS Library 1.1.1
12230 * Copyright(c) 2006-2007, Ext JS, LLC.
12232 * Originally Released Under LGPL - original licence link has changed is not relivant.
12235 * <script type="text/javascript">
12238 // Base class for reading structured data from a data source. This class is intended to be
12239 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12242 * @class Roo.data.DataReader
12243 * Base class for reading structured data from a data source. This class is intended to be
12244 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12247 Roo.data.DataReader = function(meta, recordType){
12251 this.recordType = recordType instanceof Array ?
12252 Roo.data.Record.create(recordType) : recordType;
12255 Roo.data.DataReader.prototype = {
12257 * Create an empty record
12258 * @param {Object} data (optional) - overlay some values
12259 * @return {Roo.data.Record} record created.
12261 newRow : function(d) {
12263 this.recordType.prototype.fields.each(function(c) {
12265 case 'int' : da[c.name] = 0; break;
12266 case 'date' : da[c.name] = new Date(); break;
12267 case 'float' : da[c.name] = 0.0; break;
12268 case 'boolean' : da[c.name] = false; break;
12269 default : da[c.name] = ""; break;
12273 return new this.recordType(Roo.apply(da, d));
12278 * Ext JS Library 1.1.1
12279 * Copyright(c) 2006-2007, Ext JS, LLC.
12281 * Originally Released Under LGPL - original licence link has changed is not relivant.
12284 * <script type="text/javascript">
12288 * @class Roo.data.DataProxy
12289 * @extends Roo.data.Observable
12290 * This class is an abstract base class for implementations which provide retrieval of
12291 * unformatted data objects.<br>
12293 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12294 * (of the appropriate type which knows how to parse the data object) to provide a block of
12295 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12297 * Custom implementations must implement the load method as described in
12298 * {@link Roo.data.HttpProxy#load}.
12300 Roo.data.DataProxy = function(){
12303 * @event beforeload
12304 * Fires before a network request is made to retrieve a data object.
12305 * @param {Object} This DataProxy object.
12306 * @param {Object} params The params parameter to the load function.
12311 * Fires before the load method's callback is called.
12312 * @param {Object} This DataProxy object.
12313 * @param {Object} o The data object.
12314 * @param {Object} arg The callback argument object passed to the load function.
12318 * @event loadexception
12319 * Fires if an Exception occurs during data retrieval.
12320 * @param {Object} This DataProxy object.
12321 * @param {Object} o The data object.
12322 * @param {Object} arg The callback argument object passed to the load function.
12323 * @param {Object} e The Exception.
12325 loadexception : true
12327 Roo.data.DataProxy.superclass.constructor.call(this);
12330 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12333 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12337 * Ext JS Library 1.1.1
12338 * Copyright(c) 2006-2007, Ext JS, LLC.
12340 * Originally Released Under LGPL - original licence link has changed is not relivant.
12343 * <script type="text/javascript">
12346 * @class Roo.data.MemoryProxy
12347 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12348 * to the Reader when its load method is called.
12350 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12352 Roo.data.MemoryProxy = function(data){
12356 Roo.data.MemoryProxy.superclass.constructor.call(this);
12360 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12363 * Load data from the requested source (in this case an in-memory
12364 * data object passed to the constructor), read the data object into
12365 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12366 * process that block using the passed callback.
12367 * @param {Object} params This parameter is not used by the MemoryProxy class.
12368 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12369 * object into a block of Roo.data.Records.
12370 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12371 * The function must be passed <ul>
12372 * <li>The Record block object</li>
12373 * <li>The "arg" argument from the load function</li>
12374 * <li>A boolean success indicator</li>
12376 * @param {Object} scope The scope in which to call the callback
12377 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12379 load : function(params, reader, callback, scope, arg){
12380 params = params || {};
12383 result = reader.readRecords(params.data ? params.data :this.data);
12385 this.fireEvent("loadexception", this, arg, null, e);
12386 callback.call(scope, null, arg, false);
12389 callback.call(scope, result, arg, true);
12393 update : function(params, records){
12398 * Ext JS Library 1.1.1
12399 * Copyright(c) 2006-2007, Ext JS, LLC.
12401 * Originally Released Under LGPL - original licence link has changed is not relivant.
12404 * <script type="text/javascript">
12407 * @class Roo.data.HttpProxy
12408 * @extends Roo.data.DataProxy
12409 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12410 * configured to reference a certain URL.<br><br>
12412 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12413 * from which the running page was served.<br><br>
12415 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12417 * Be aware that to enable the browser to parse an XML document, the server must set
12418 * the Content-Type header in the HTTP response to "text/xml".
12420 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12421 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12422 * will be used to make the request.
12424 Roo.data.HttpProxy = function(conn){
12425 Roo.data.HttpProxy.superclass.constructor.call(this);
12426 // is conn a conn config or a real conn?
12428 this.useAjax = !conn || !conn.events;
12432 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12433 // thse are take from connection...
12436 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12439 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12440 * extra parameters to each request made by this object. (defaults to undefined)
12443 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12444 * to each request made by this object. (defaults to undefined)
12447 * @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)
12450 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12453 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12459 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12463 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12464 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12465 * a finer-grained basis than the DataProxy events.
12467 getConnection : function(){
12468 return this.useAjax ? Roo.Ajax : this.conn;
12472 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12473 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12474 * process that block using the passed callback.
12475 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12476 * for the request to the remote server.
12477 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12478 * object into a block of Roo.data.Records.
12479 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12480 * The function must be passed <ul>
12481 * <li>The Record block object</li>
12482 * <li>The "arg" argument from the load function</li>
12483 * <li>A boolean success indicator</li>
12485 * @param {Object} scope The scope in which to call the callback
12486 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12488 load : function(params, reader, callback, scope, arg){
12489 if(this.fireEvent("beforeload", this, params) !== false){
12491 params : params || {},
12493 callback : callback,
12498 callback : this.loadResponse,
12502 Roo.applyIf(o, this.conn);
12503 if(this.activeRequest){
12504 Roo.Ajax.abort(this.activeRequest);
12506 this.activeRequest = Roo.Ajax.request(o);
12508 this.conn.request(o);
12511 callback.call(scope||this, null, arg, false);
12516 loadResponse : function(o, success, response){
12517 delete this.activeRequest;
12519 this.fireEvent("loadexception", this, o, response);
12520 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12525 result = o.reader.read(response);
12527 this.fireEvent("loadexception", this, o, response, e);
12528 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12532 this.fireEvent("load", this, o, o.request.arg);
12533 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12537 update : function(dataSet){
12542 updateResponse : function(dataSet){
12547 * Ext JS Library 1.1.1
12548 * Copyright(c) 2006-2007, Ext JS, LLC.
12550 * Originally Released Under LGPL - original licence link has changed is not relivant.
12553 * <script type="text/javascript">
12557 * @class Roo.data.ScriptTagProxy
12558 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12559 * other than the originating domain of the running page.<br><br>
12561 * <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
12562 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12564 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12565 * source code that is used as the source inside a <script> tag.<br><br>
12567 * In order for the browser to process the returned data, the server must wrap the data object
12568 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12569 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12570 * depending on whether the callback name was passed:
12573 boolean scriptTag = false;
12574 String cb = request.getParameter("callback");
12577 response.setContentType("text/javascript");
12579 response.setContentType("application/x-json");
12581 Writer out = response.getWriter();
12583 out.write(cb + "(");
12585 out.print(dataBlock.toJsonString());
12592 * @param {Object} config A configuration object.
12594 Roo.data.ScriptTagProxy = function(config){
12595 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12596 Roo.apply(this, config);
12597 this.head = document.getElementsByTagName("head")[0];
12600 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12602 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12604 * @cfg {String} url The URL from which to request the data object.
12607 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12611 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12612 * the server the name of the callback function set up by the load call to process the returned data object.
12613 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12614 * javascript output which calls this named function passing the data object as its only parameter.
12616 callbackParam : "callback",
12618 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12619 * name to the request.
12624 * Load data from the configured URL, read the data object into
12625 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12626 * process that block using the passed callback.
12627 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12628 * for the request to the remote server.
12629 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12630 * object into a block of Roo.data.Records.
12631 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12632 * The function must be passed <ul>
12633 * <li>The Record block object</li>
12634 * <li>The "arg" argument from the load function</li>
12635 * <li>A boolean success indicator</li>
12637 * @param {Object} scope The scope in which to call the callback
12638 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12640 load : function(params, reader, callback, scope, arg){
12641 if(this.fireEvent("beforeload", this, params) !== false){
12643 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12645 var url = this.url;
12646 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12648 url += "&_dc=" + (new Date().getTime());
12650 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12653 cb : "stcCallback"+transId,
12654 scriptId : "stcScript"+transId,
12658 callback : callback,
12664 window[trans.cb] = function(o){
12665 conn.handleResponse(o, trans);
12668 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12670 if(this.autoAbort !== false){
12674 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12676 var script = document.createElement("script");
12677 script.setAttribute("src", url);
12678 script.setAttribute("type", "text/javascript");
12679 script.setAttribute("id", trans.scriptId);
12680 this.head.appendChild(script);
12682 this.trans = trans;
12684 callback.call(scope||this, null, arg, false);
12689 isLoading : function(){
12690 return this.trans ? true : false;
12694 * Abort the current server request.
12696 abort : function(){
12697 if(this.isLoading()){
12698 this.destroyTrans(this.trans);
12703 destroyTrans : function(trans, isLoaded){
12704 this.head.removeChild(document.getElementById(trans.scriptId));
12705 clearTimeout(trans.timeoutId);
12707 window[trans.cb] = undefined;
12709 delete window[trans.cb];
12712 // if hasn't been loaded, wait for load to remove it to prevent script error
12713 window[trans.cb] = function(){
12714 window[trans.cb] = undefined;
12716 delete window[trans.cb];
12723 handleResponse : function(o, trans){
12724 this.trans = false;
12725 this.destroyTrans(trans, true);
12728 result = trans.reader.readRecords(o);
12730 this.fireEvent("loadexception", this, o, trans.arg, e);
12731 trans.callback.call(trans.scope||window, null, trans.arg, false);
12734 this.fireEvent("load", this, o, trans.arg);
12735 trans.callback.call(trans.scope||window, result, trans.arg, true);
12739 handleFailure : function(trans){
12740 this.trans = false;
12741 this.destroyTrans(trans, false);
12742 this.fireEvent("loadexception", this, null, trans.arg);
12743 trans.callback.call(trans.scope||window, null, trans.arg, false);
12747 * Ext JS Library 1.1.1
12748 * Copyright(c) 2006-2007, Ext JS, LLC.
12750 * Originally Released Under LGPL - original licence link has changed is not relivant.
12753 * <script type="text/javascript">
12757 * @class Roo.data.JsonReader
12758 * @extends Roo.data.DataReader
12759 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12760 * based on mappings in a provided Roo.data.Record constructor.
12762 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12763 * in the reply previously.
12768 var RecordDef = Roo.data.Record.create([
12769 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12770 {name: 'occupation'} // This field will use "occupation" as the mapping.
12772 var myReader = new Roo.data.JsonReader({
12773 totalProperty: "results", // The property which contains the total dataset size (optional)
12774 root: "rows", // The property which contains an Array of row objects
12775 id: "id" // The property within each row object that provides an ID for the record (optional)
12779 * This would consume a JSON file like this:
12781 { 'results': 2, 'rows': [
12782 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12783 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12786 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12787 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12788 * paged from the remote server.
12789 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12790 * @cfg {String} root name of the property which contains the Array of row objects.
12791 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12792 * @cfg {Array} fields Array of field definition objects
12794 * Create a new JsonReader
12795 * @param {Object} meta Metadata configuration options
12796 * @param {Object} recordType Either an Array of field definition objects,
12797 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12799 Roo.data.JsonReader = function(meta, recordType){
12802 // set some defaults:
12803 Roo.applyIf(meta, {
12804 totalProperty: 'total',
12805 successProperty : 'success',
12810 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12812 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12815 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12816 * Used by Store query builder to append _requestMeta to params.
12819 metaFromRemote : false,
12821 * This method is only used by a DataProxy which has retrieved data from a remote server.
12822 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12823 * @return {Object} data A data block which is used by an Roo.data.Store object as
12824 * a cache of Roo.data.Records.
12826 read : function(response){
12827 var json = response.responseText;
12829 var o = /* eval:var:o */ eval("("+json+")");
12831 throw {message: "JsonReader.read: Json object not found"};
12837 this.metaFromRemote = true;
12838 this.meta = o.metaData;
12839 this.recordType = Roo.data.Record.create(o.metaData.fields);
12840 this.onMetaChange(this.meta, this.recordType, o);
12842 return this.readRecords(o);
12845 // private function a store will implement
12846 onMetaChange : function(meta, recordType, o){
12853 simpleAccess: function(obj, subsc) {
12860 getJsonAccessor: function(){
12862 return function(expr) {
12864 return(re.test(expr))
12865 ? new Function("obj", "return obj." + expr)
12870 return Roo.emptyFn;
12875 * Create a data block containing Roo.data.Records from an XML document.
12876 * @param {Object} o An object which contains an Array of row objects in the property specified
12877 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12878 * which contains the total size of the dataset.
12879 * @return {Object} data A data block which is used by an Roo.data.Store object as
12880 * a cache of Roo.data.Records.
12882 readRecords : function(o){
12884 * After any data loads, the raw JSON data is available for further custom processing.
12888 var s = this.meta, Record = this.recordType,
12889 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12891 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12893 if(s.totalProperty) {
12894 this.getTotal = this.getJsonAccessor(s.totalProperty);
12896 if(s.successProperty) {
12897 this.getSuccess = this.getJsonAccessor(s.successProperty);
12899 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12901 var g = this.getJsonAccessor(s.id);
12902 this.getId = function(rec) {
12904 return (r === undefined || r === "") ? null : r;
12907 this.getId = function(){return null;};
12910 for(var jj = 0; jj < fl; jj++){
12912 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12913 this.ef[jj] = this.getJsonAccessor(map);
12917 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12918 if(s.totalProperty){
12919 var vt = parseInt(this.getTotal(o), 10);
12924 if(s.successProperty){
12925 var vs = this.getSuccess(o);
12926 if(vs === false || vs === 'false'){
12931 for(var i = 0; i < c; i++){
12934 var id = this.getId(n);
12935 for(var j = 0; j < fl; j++){
12937 var v = this.ef[j](n);
12939 Roo.log('missing convert for ' + f.name);
12943 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12945 var record = new Record(values, id);
12947 records[i] = record;
12953 totalRecords : totalRecords
12958 * Ext JS Library 1.1.1
12959 * Copyright(c) 2006-2007, Ext JS, LLC.
12961 * Originally Released Under LGPL - original licence link has changed is not relivant.
12964 * <script type="text/javascript">
12968 * @class Roo.data.ArrayReader
12969 * @extends Roo.data.DataReader
12970 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12971 * Each element of that Array represents a row of data fields. The
12972 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12973 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12977 var RecordDef = Roo.data.Record.create([
12978 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12979 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12981 var myReader = new Roo.data.ArrayReader({
12982 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12986 * This would consume an Array like this:
12988 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12990 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12992 * Create a new JsonReader
12993 * @param {Object} meta Metadata configuration options.
12994 * @param {Object} recordType Either an Array of field definition objects
12995 * @cfg {Array} fields Array of field definition objects
12996 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12997 * as specified to {@link Roo.data.Record#create},
12998 * or an {@link Roo.data.Record} object
12999 * created using {@link Roo.data.Record#create}.
13001 Roo.data.ArrayReader = function(meta, recordType){
13004 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13007 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13009 * Create a data block containing Roo.data.Records from an XML document.
13010 * @param {Object} o An Array of row objects which represents the dataset.
13011 * @return {Object} data A data block which is used by an Roo.data.Store object as
13012 * a cache of Roo.data.Records.
13014 readRecords : function(o){
13015 var sid = this.meta ? this.meta.id : null;
13016 var recordType = this.recordType, fields = recordType.prototype.fields;
13019 for(var i = 0; i < root.length; i++){
13022 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13023 for(var j = 0, jlen = fields.length; j < jlen; j++){
13024 var f = fields.items[j];
13025 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13026 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13028 values[f.name] = v;
13030 var record = new recordType(values, id);
13032 records[records.length] = record;
13036 totalRecords : records.length
13045 * @class Roo.bootstrap.ComboBox
13046 * @extends Roo.bootstrap.TriggerField
13047 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13048 * @cfg {Boolean} append (true|false) default false
13049 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13050 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13051 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13052 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13053 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13054 * @cfg {Boolean} animate default true
13055 * @cfg {Boolean} emptyResultText only for touch device
13056 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13057 * @cfg {String} emptyTitle default ''
13059 * Create a new ComboBox.
13060 * @param {Object} config Configuration options
13062 Roo.bootstrap.ComboBox = function(config){
13063 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13067 * Fires when the dropdown list is expanded
13068 * @param {Roo.bootstrap.ComboBox} combo This combo box
13073 * Fires when the dropdown list is collapsed
13074 * @param {Roo.bootstrap.ComboBox} combo This combo box
13078 * @event beforeselect
13079 * Fires before a list item is selected. Return false to cancel the selection.
13080 * @param {Roo.bootstrap.ComboBox} combo This combo box
13081 * @param {Roo.data.Record} record The data record returned from the underlying store
13082 * @param {Number} index The index of the selected item in the dropdown list
13084 'beforeselect' : true,
13087 * Fires when a list item is selected
13088 * @param {Roo.bootstrap.ComboBox} combo This combo box
13089 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13090 * @param {Number} index The index of the selected item in the dropdown list
13094 * @event beforequery
13095 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13096 * The event object passed has these properties:
13097 * @param {Roo.bootstrap.ComboBox} combo This combo box
13098 * @param {String} query The query
13099 * @param {Boolean} forceAll true to force "all" query
13100 * @param {Boolean} cancel true to cancel the query
13101 * @param {Object} e The query event object
13103 'beforequery': true,
13106 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13107 * @param {Roo.bootstrap.ComboBox} combo This combo box
13112 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13113 * @param {Roo.bootstrap.ComboBox} combo This combo box
13114 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13119 * Fires when the remove value from the combobox array
13120 * @param {Roo.bootstrap.ComboBox} combo This combo box
13124 * @event afterremove
13125 * Fires when the remove value from the combobox array
13126 * @param {Roo.bootstrap.ComboBox} combo This combo box
13128 'afterremove' : true,
13130 * @event specialfilter
13131 * Fires when specialfilter
13132 * @param {Roo.bootstrap.ComboBox} combo This combo box
13134 'specialfilter' : true,
13137 * Fires when tick the element
13138 * @param {Roo.bootstrap.ComboBox} combo This combo box
13142 * @event touchviewdisplay
13143 * Fires when touch view require special display (default is using displayField)
13144 * @param {Roo.bootstrap.ComboBox} combo This combo box
13145 * @param {Object} cfg set html .
13147 'touchviewdisplay' : true
13152 this.tickItems = [];
13154 this.selectedIndex = -1;
13155 if(this.mode == 'local'){
13156 if(config.queryDelay === undefined){
13157 this.queryDelay = 10;
13159 if(config.minChars === undefined){
13165 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13168 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13169 * rendering into an Roo.Editor, defaults to false)
13172 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13173 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13176 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13179 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13180 * the dropdown list (defaults to undefined, with no header element)
13184 * @cfg {String/Roo.Template} tpl The template to use to render the output
13188 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13190 listWidth: undefined,
13192 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13193 * mode = 'remote' or 'text' if mode = 'local')
13195 displayField: undefined,
13198 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13199 * mode = 'remote' or 'value' if mode = 'local').
13200 * Note: use of a valueField requires the user make a selection
13201 * in order for a value to be mapped.
13203 valueField: undefined,
13205 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13210 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13211 * field's data value (defaults to the underlying DOM element's name)
13213 hiddenName: undefined,
13215 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13219 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13221 selectedClass: 'active',
13224 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13228 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13229 * anchor positions (defaults to 'tl-bl')
13231 listAlign: 'tl-bl?',
13233 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13237 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13238 * query specified by the allQuery config option (defaults to 'query')
13240 triggerAction: 'query',
13242 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13243 * (defaults to 4, does not apply if editable = false)
13247 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13248 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13252 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13253 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13257 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13258 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13262 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13263 * when editable = true (defaults to false)
13265 selectOnFocus:false,
13267 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13269 queryParam: 'query',
13271 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13272 * when mode = 'remote' (defaults to 'Loading...')
13274 loadingText: 'Loading...',
13276 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13280 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13284 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13285 * traditional select (defaults to true)
13289 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13293 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13297 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13298 * listWidth has a higher value)
13302 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13303 * allow the user to set arbitrary text into the field (defaults to false)
13305 forceSelection:false,
13307 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13308 * if typeAhead = true (defaults to 250)
13310 typeAheadDelay : 250,
13312 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13313 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13315 valueNotFoundText : undefined,
13317 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13319 blockFocus : false,
13322 * @cfg {Boolean} disableClear Disable showing of clear button.
13324 disableClear : false,
13326 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13328 alwaysQuery : false,
13331 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13336 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13338 invalidClass : "has-warning",
13341 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13343 validClass : "has-success",
13346 * @cfg {Boolean} specialFilter (true|false) special filter default false
13348 specialFilter : false,
13351 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13353 mobileTouchView : true,
13356 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13358 useNativeIOS : false,
13361 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13363 mobile_restrict_height : false,
13365 ios_options : false,
13377 btnPosition : 'right',
13378 triggerList : true,
13379 showToggleBtn : true,
13381 emptyResultText: 'Empty',
13382 triggerText : 'Select',
13385 // element that contains real text value.. (when hidden is used..)
13387 getAutoCreate : function()
13392 * Render classic select for iso
13395 if(Roo.isIOS && this.useNativeIOS){
13396 cfg = this.getAutoCreateNativeIOS();
13404 if(Roo.isTouch && this.mobileTouchView){
13405 cfg = this.getAutoCreateTouchView();
13412 if(!this.tickable){
13413 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13418 * ComboBox with tickable selections
13421 var align = this.labelAlign || this.parentLabelAlign();
13424 cls : 'form-group roo-combobox-tickable' //input-group
13427 var btn_text_select = '';
13428 var btn_text_done = '';
13429 var btn_text_cancel = '';
13431 if (this.btn_text_show) {
13432 btn_text_select = 'Select';
13433 btn_text_done = 'Done';
13434 btn_text_cancel = 'Cancel';
13439 cls : 'tickable-buttons',
13444 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13445 //html : this.triggerText
13446 html: btn_text_select
13452 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13454 html: btn_text_done
13460 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13462 html: btn_text_cancel
13468 buttons.cn.unshift({
13470 cls: 'roo-select2-search-field-input'
13476 Roo.each(buttons.cn, function(c){
13478 c.cls += ' btn-' + _this.size;
13481 if (_this.disabled) {
13488 style : 'display: contents',
13493 cls: 'form-hidden-field'
13497 cls: 'roo-select2-choices',
13501 cls: 'roo-select2-search-field',
13512 cls: 'roo-select2-container input-group roo-select2-container-multi',
13518 // cls: 'typeahead typeahead-long dropdown-menu',
13519 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13524 if(this.hasFeedback && !this.allowBlank){
13528 cls: 'glyphicon form-control-feedback'
13531 combobox.cn.push(feedback);
13536 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13537 tooltip : 'This field is required'
13539 if (Roo.bootstrap.version == 4) {
13542 style : 'display:none'
13545 if (align ==='left' && this.fieldLabel.length) {
13547 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13554 cls : 'control-label col-form-label',
13555 html : this.fieldLabel
13567 var labelCfg = cfg.cn[1];
13568 var contentCfg = cfg.cn[2];
13571 if(this.indicatorpos == 'right'){
13577 cls : 'control-label col-form-label',
13581 html : this.fieldLabel
13597 labelCfg = cfg.cn[0];
13598 contentCfg = cfg.cn[1];
13602 if(this.labelWidth > 12){
13603 labelCfg.style = "width: " + this.labelWidth + 'px';
13606 if(this.labelWidth < 13 && this.labelmd == 0){
13607 this.labelmd = this.labelWidth;
13610 if(this.labellg > 0){
13611 labelCfg.cls += ' col-lg-' + this.labellg;
13612 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13615 if(this.labelmd > 0){
13616 labelCfg.cls += ' col-md-' + this.labelmd;
13617 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13620 if(this.labelsm > 0){
13621 labelCfg.cls += ' col-sm-' + this.labelsm;
13622 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13625 if(this.labelxs > 0){
13626 labelCfg.cls += ' col-xs-' + this.labelxs;
13627 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13631 } else if ( this.fieldLabel.length) {
13632 // Roo.log(" label");
13637 //cls : 'input-group-addon',
13638 html : this.fieldLabel
13643 if(this.indicatorpos == 'right'){
13647 //cls : 'input-group-addon',
13648 html : this.fieldLabel
13658 // Roo.log(" no label && no align");
13665 ['xs','sm','md','lg'].map(function(size){
13666 if (settings[size]) {
13667 cfg.cls += ' col-' + size + '-' + settings[size];
13675 _initEventsCalled : false,
13678 initEvents: function()
13680 if (this._initEventsCalled) { // as we call render... prevent looping...
13683 this._initEventsCalled = true;
13686 throw "can not find store for combo";
13689 this.indicator = this.indicatorEl();
13691 this.store = Roo.factory(this.store, Roo.data);
13692 this.store.parent = this;
13694 // if we are building from html. then this element is so complex, that we can not really
13695 // use the rendered HTML.
13696 // so we have to trash and replace the previous code.
13697 if (Roo.XComponent.build_from_html) {
13698 // remove this element....
13699 var e = this.el.dom, k=0;
13700 while (e ) { e = e.previousSibling; ++k;}
13705 this.rendered = false;
13707 this.render(this.parent().getChildContainer(true), k);
13710 if(Roo.isIOS && this.useNativeIOS){
13711 this.initIOSView();
13719 if(Roo.isTouch && this.mobileTouchView){
13720 this.initTouchView();
13725 this.initTickableEvents();
13729 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13731 if(this.hiddenName){
13733 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13735 this.hiddenField.dom.value =
13736 this.hiddenValue !== undefined ? this.hiddenValue :
13737 this.value !== undefined ? this.value : '';
13739 // prevent input submission
13740 this.el.dom.removeAttribute('name');
13741 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13746 // this.el.dom.setAttribute('autocomplete', 'off');
13749 var cls = 'x-combo-list';
13751 //this.list = new Roo.Layer({
13752 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13758 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13759 _this.list.setWidth(lw);
13762 this.list.on('mouseover', this.onViewOver, this);
13763 this.list.on('mousemove', this.onViewMove, this);
13764 this.list.on('scroll', this.onViewScroll, this);
13767 this.list.swallowEvent('mousewheel');
13768 this.assetHeight = 0;
13771 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13772 this.assetHeight += this.header.getHeight();
13775 this.innerList = this.list.createChild({cls:cls+'-inner'});
13776 this.innerList.on('mouseover', this.onViewOver, this);
13777 this.innerList.on('mousemove', this.onViewMove, this);
13778 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13780 if(this.allowBlank && !this.pageSize && !this.disableClear){
13781 this.footer = this.list.createChild({cls:cls+'-ft'});
13782 this.pageTb = new Roo.Toolbar(this.footer);
13786 this.footer = this.list.createChild({cls:cls+'-ft'});
13787 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13788 {pageSize: this.pageSize});
13792 if (this.pageTb && this.allowBlank && !this.disableClear) {
13794 this.pageTb.add(new Roo.Toolbar.Fill(), {
13795 cls: 'x-btn-icon x-btn-clear',
13797 handler: function()
13800 _this.clearValue();
13801 _this.onSelect(false, -1);
13806 this.assetHeight += this.footer.getHeight();
13811 this.tpl = Roo.bootstrap.version == 4 ?
13812 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13813 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13816 this.view = new Roo.View(this.list, this.tpl, {
13817 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13819 //this.view.wrapEl.setDisplayed(false);
13820 this.view.on('click', this.onViewClick, this);
13823 this.store.on('beforeload', this.onBeforeLoad, this);
13824 this.store.on('load', this.onLoad, this);
13825 this.store.on('loadexception', this.onLoadException, this);
13827 if(this.resizable){
13828 this.resizer = new Roo.Resizable(this.list, {
13829 pinned:true, handles:'se'
13831 this.resizer.on('resize', function(r, w, h){
13832 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13833 this.listWidth = w;
13834 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13835 this.restrictHeight();
13837 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13840 if(!this.editable){
13841 this.editable = true;
13842 this.setEditable(false);
13847 if (typeof(this.events.add.listeners) != 'undefined') {
13849 this.addicon = this.wrap.createChild(
13850 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13852 this.addicon.on('click', function(e) {
13853 this.fireEvent('add', this);
13856 if (typeof(this.events.edit.listeners) != 'undefined') {
13858 this.editicon = this.wrap.createChild(
13859 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13860 if (this.addicon) {
13861 this.editicon.setStyle('margin-left', '40px');
13863 this.editicon.on('click', function(e) {
13865 // we fire even if inothing is selected..
13866 this.fireEvent('edit', this, this.lastData );
13872 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13873 "up" : function(e){
13874 this.inKeyMode = true;
13878 "down" : function(e){
13879 if(!this.isExpanded()){
13880 this.onTriggerClick();
13882 this.inKeyMode = true;
13887 "enter" : function(e){
13888 // this.onViewClick();
13892 if(this.fireEvent("specialkey", this, e)){
13893 this.onViewClick(false);
13899 "esc" : function(e){
13903 "tab" : function(e){
13906 if(this.fireEvent("specialkey", this, e)){
13907 this.onViewClick(false);
13915 doRelay : function(foo, bar, hname){
13916 if(hname == 'down' || this.scope.isExpanded()){
13917 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13926 this.queryDelay = Math.max(this.queryDelay || 10,
13927 this.mode == 'local' ? 10 : 250);
13930 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13932 if(this.typeAhead){
13933 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13935 if(this.editable !== false){
13936 this.inputEl().on("keyup", this.onKeyUp, this);
13938 if(this.forceSelection){
13939 this.inputEl().on('blur', this.doForce, this);
13943 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13944 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13948 initTickableEvents: function()
13952 if(this.hiddenName){
13954 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13956 this.hiddenField.dom.value =
13957 this.hiddenValue !== undefined ? this.hiddenValue :
13958 this.value !== undefined ? this.value : '';
13960 // prevent input submission
13961 this.el.dom.removeAttribute('name');
13962 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13967 // this.list = this.el.select('ul.dropdown-menu',true).first();
13969 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13970 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13971 if(this.triggerList){
13972 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13975 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13976 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13978 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13979 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13981 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13982 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13984 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13985 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13986 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13989 this.cancelBtn.hide();
13994 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13995 _this.list.setWidth(lw);
13998 this.list.on('mouseover', this.onViewOver, this);
13999 this.list.on('mousemove', this.onViewMove, this);
14001 this.list.on('scroll', this.onViewScroll, this);
14004 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14005 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14008 this.view = new Roo.View(this.list, this.tpl, {
14013 selectedClass: this.selectedClass
14016 //this.view.wrapEl.setDisplayed(false);
14017 this.view.on('click', this.onViewClick, this);
14021 this.store.on('beforeload', this.onBeforeLoad, this);
14022 this.store.on('load', this.onLoad, this);
14023 this.store.on('loadexception', this.onLoadException, this);
14026 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14027 "up" : function(e){
14028 this.inKeyMode = true;
14032 "down" : function(e){
14033 this.inKeyMode = true;
14037 "enter" : function(e){
14038 if(this.fireEvent("specialkey", this, e)){
14039 this.onViewClick(false);
14045 "esc" : function(e){
14046 this.onTickableFooterButtonClick(e, false, false);
14049 "tab" : function(e){
14050 this.fireEvent("specialkey", this, e);
14052 this.onTickableFooterButtonClick(e, false, false);
14059 doRelay : function(e, fn, key){
14060 if(this.scope.isExpanded()){
14061 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14070 this.queryDelay = Math.max(this.queryDelay || 10,
14071 this.mode == 'local' ? 10 : 250);
14074 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14076 if(this.typeAhead){
14077 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14080 if(this.editable !== false){
14081 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14084 this.indicator = this.indicatorEl();
14086 if(this.indicator){
14087 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14088 this.indicator.hide();
14093 onDestroy : function(){
14095 this.view.setStore(null);
14096 this.view.el.removeAllListeners();
14097 this.view.el.remove();
14098 this.view.purgeListeners();
14101 this.list.dom.innerHTML = '';
14105 this.store.un('beforeload', this.onBeforeLoad, this);
14106 this.store.un('load', this.onLoad, this);
14107 this.store.un('loadexception', this.onLoadException, this);
14109 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14113 fireKey : function(e){
14114 if(e.isNavKeyPress() && !this.list.isVisible()){
14115 this.fireEvent("specialkey", this, e);
14120 onResize: function(w, h){
14121 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14123 // if(typeof w != 'number'){
14124 // // we do not handle it!?!?
14127 // var tw = this.trigger.getWidth();
14128 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14129 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14131 // this.inputEl().setWidth( this.adjustWidth('input', x));
14133 // //this.trigger.setStyle('left', x+'px');
14135 // if(this.list && this.listWidth === undefined){
14136 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14137 // this.list.setWidth(lw);
14138 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14146 * Allow or prevent the user from directly editing the field text. If false is passed,
14147 * the user will only be able to select from the items defined in the dropdown list. This method
14148 * is the runtime equivalent of setting the 'editable' config option at config time.
14149 * @param {Boolean} value True to allow the user to directly edit the field text
14151 setEditable : function(value){
14152 if(value == this.editable){
14155 this.editable = value;
14157 this.inputEl().dom.setAttribute('readOnly', true);
14158 this.inputEl().on('mousedown', this.onTriggerClick, this);
14159 this.inputEl().addClass('x-combo-noedit');
14161 this.inputEl().dom.setAttribute('readOnly', false);
14162 this.inputEl().un('mousedown', this.onTriggerClick, this);
14163 this.inputEl().removeClass('x-combo-noedit');
14169 onBeforeLoad : function(combo,opts){
14170 if(!this.hasFocus){
14174 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14176 this.restrictHeight();
14177 this.selectedIndex = -1;
14181 onLoad : function(){
14183 this.hasQuery = false;
14185 if(!this.hasFocus){
14189 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14190 this.loading.hide();
14193 if(this.store.getCount() > 0){
14196 this.restrictHeight();
14197 if(this.lastQuery == this.allQuery){
14198 if(this.editable && !this.tickable){
14199 this.inputEl().dom.select();
14203 !this.selectByValue(this.value, true) &&
14206 !this.store.lastOptions ||
14207 typeof(this.store.lastOptions.add) == 'undefined' ||
14208 this.store.lastOptions.add != true
14211 this.select(0, true);
14214 if(this.autoFocus){
14217 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14218 this.taTask.delay(this.typeAheadDelay);
14222 this.onEmptyResults();
14228 onLoadException : function()
14230 this.hasQuery = false;
14232 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14233 this.loading.hide();
14236 if(this.tickable && this.editable){
14241 // only causes errors at present
14242 //Roo.log(this.store.reader.jsonData);
14243 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14245 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14251 onTypeAhead : function(){
14252 if(this.store.getCount() > 0){
14253 var r = this.store.getAt(0);
14254 var newValue = r.data[this.displayField];
14255 var len = newValue.length;
14256 var selStart = this.getRawValue().length;
14258 if(selStart != len){
14259 this.setRawValue(newValue);
14260 this.selectText(selStart, newValue.length);
14266 onSelect : function(record, index){
14268 if(this.fireEvent('beforeselect', this, record, index) !== false){
14270 this.setFromData(index > -1 ? record.data : false);
14273 this.fireEvent('select', this, record, index);
14278 * Returns the currently selected field value or empty string if no value is set.
14279 * @return {String} value The selected value
14281 getValue : function()
14283 if(Roo.isIOS && this.useNativeIOS){
14284 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14288 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14291 if(this.valueField){
14292 return typeof this.value != 'undefined' ? this.value : '';
14294 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14298 getRawValue : function()
14300 if(Roo.isIOS && this.useNativeIOS){
14301 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14304 var v = this.inputEl().getValue();
14310 * Clears any text/value currently set in the field
14312 clearValue : function(){
14314 if(this.hiddenField){
14315 this.hiddenField.dom.value = '';
14318 this.setRawValue('');
14319 this.lastSelectionText = '';
14320 this.lastData = false;
14322 var close = this.closeTriggerEl();
14333 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14334 * will be displayed in the field. If the value does not match the data value of an existing item,
14335 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14336 * Otherwise the field will be blank (although the value will still be set).
14337 * @param {String} value The value to match
14339 setValue : function(v)
14341 if(Roo.isIOS && this.useNativeIOS){
14342 this.setIOSValue(v);
14352 if(this.valueField){
14353 var r = this.findRecord(this.valueField, v);
14355 text = r.data[this.displayField];
14356 }else if(this.valueNotFoundText !== undefined){
14357 text = this.valueNotFoundText;
14360 this.lastSelectionText = text;
14361 if(this.hiddenField){
14362 this.hiddenField.dom.value = v;
14364 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14367 var close = this.closeTriggerEl();
14370 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14376 * @property {Object} the last set data for the element
14381 * Sets the value of the field based on a object which is related to the record format for the store.
14382 * @param {Object} value the value to set as. or false on reset?
14384 setFromData : function(o){
14391 var dv = ''; // display value
14392 var vv = ''; // value value..
14394 if (this.displayField) {
14395 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14397 // this is an error condition!!!
14398 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14401 if(this.valueField){
14402 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14405 var close = this.closeTriggerEl();
14408 if(dv.length || vv * 1 > 0){
14410 this.blockFocus=true;
14416 if(this.hiddenField){
14417 this.hiddenField.dom.value = vv;
14419 this.lastSelectionText = dv;
14420 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14424 // no hidden field.. - we store the value in 'value', but still display
14425 // display field!!!!
14426 this.lastSelectionText = dv;
14427 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14434 reset : function(){
14435 // overridden so that last data is reset..
14442 this.setValue(this.originalValue);
14443 //this.clearInvalid();
14444 this.lastData = false;
14446 this.view.clearSelections();
14452 findRecord : function(prop, value){
14454 if(this.store.getCount() > 0){
14455 this.store.each(function(r){
14456 if(r.data[prop] == value){
14466 getName: function()
14468 // returns hidden if it's set..
14469 if (!this.rendered) {return ''};
14470 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14474 onViewMove : function(e, t){
14475 this.inKeyMode = false;
14479 onViewOver : function(e, t){
14480 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14483 var item = this.view.findItemFromChild(t);
14486 var index = this.view.indexOf(item);
14487 this.select(index, false);
14492 onViewClick : function(view, doFocus, el, e)
14494 var index = this.view.getSelectedIndexes()[0];
14496 var r = this.store.getAt(index);
14500 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14507 Roo.each(this.tickItems, function(v,k){
14509 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14511 _this.tickItems.splice(k, 1);
14513 if(typeof(e) == 'undefined' && view == false){
14514 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14526 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14527 this.tickItems.push(r.data);
14530 if(typeof(e) == 'undefined' && view == false){
14531 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14538 this.onSelect(r, index);
14540 if(doFocus !== false && !this.blockFocus){
14541 this.inputEl().focus();
14546 restrictHeight : function(){
14547 //this.innerList.dom.style.height = '';
14548 //var inner = this.innerList.dom;
14549 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14550 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14551 //this.list.beginUpdate();
14552 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14553 this.list.alignTo(this.inputEl(), this.listAlign);
14554 this.list.alignTo(this.inputEl(), this.listAlign);
14555 //this.list.endUpdate();
14559 onEmptyResults : function(){
14561 if(this.tickable && this.editable){
14562 this.hasFocus = false;
14563 this.restrictHeight();
14571 * Returns true if the dropdown list is expanded, else false.
14573 isExpanded : function(){
14574 return this.list.isVisible();
14578 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14579 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14580 * @param {String} value The data value of the item to select
14581 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14582 * selected item if it is not currently in view (defaults to true)
14583 * @return {Boolean} True if the value matched an item in the list, else false
14585 selectByValue : function(v, scrollIntoView){
14586 if(v !== undefined && v !== null){
14587 var r = this.findRecord(this.valueField || this.displayField, v);
14589 this.select(this.store.indexOf(r), scrollIntoView);
14597 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14598 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14599 * @param {Number} index The zero-based index of the list item to select
14600 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14601 * selected item if it is not currently in view (defaults to true)
14603 select : function(index, scrollIntoView){
14604 this.selectedIndex = index;
14605 this.view.select(index);
14606 if(scrollIntoView !== false){
14607 var el = this.view.getNode(index);
14609 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14612 this.list.scrollChildIntoView(el, false);
14618 selectNext : function(){
14619 var ct = this.store.getCount();
14621 if(this.selectedIndex == -1){
14623 }else if(this.selectedIndex < ct-1){
14624 this.select(this.selectedIndex+1);
14630 selectPrev : function(){
14631 var ct = this.store.getCount();
14633 if(this.selectedIndex == -1){
14635 }else if(this.selectedIndex != 0){
14636 this.select(this.selectedIndex-1);
14642 onKeyUp : function(e){
14643 if(this.editable !== false && !e.isSpecialKey()){
14644 this.lastKey = e.getKey();
14645 this.dqTask.delay(this.queryDelay);
14650 validateBlur : function(){
14651 return !this.list || !this.list.isVisible();
14655 initQuery : function(){
14657 var v = this.getRawValue();
14659 if(this.tickable && this.editable){
14660 v = this.tickableInputEl().getValue();
14667 doForce : function(){
14668 if(this.inputEl().dom.value.length > 0){
14669 this.inputEl().dom.value =
14670 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14676 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14677 * query allowing the query action to be canceled if needed.
14678 * @param {String} query The SQL query to execute
14679 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14680 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14681 * saved in the current store (defaults to false)
14683 doQuery : function(q, forceAll){
14685 if(q === undefined || q === null){
14690 forceAll: forceAll,
14694 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14699 forceAll = qe.forceAll;
14700 if(forceAll === true || (q.length >= this.minChars)){
14702 this.hasQuery = true;
14704 if(this.lastQuery != q || this.alwaysQuery){
14705 this.lastQuery = q;
14706 if(this.mode == 'local'){
14707 this.selectedIndex = -1;
14709 this.store.clearFilter();
14712 if(this.specialFilter){
14713 this.fireEvent('specialfilter', this);
14718 this.store.filter(this.displayField, q);
14721 this.store.fireEvent("datachanged", this.store);
14728 this.store.baseParams[this.queryParam] = q;
14730 var options = {params : this.getParams(q)};
14733 options.add = true;
14734 options.params.start = this.page * this.pageSize;
14737 this.store.load(options);
14740 * this code will make the page width larger, at the beginning, the list not align correctly,
14741 * we should expand the list on onLoad
14742 * so command out it
14747 this.selectedIndex = -1;
14752 this.loadNext = false;
14756 getParams : function(q){
14758 //p[this.queryParam] = q;
14762 p.limit = this.pageSize;
14768 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14770 collapse : function(){
14771 if(!this.isExpanded()){
14777 this.hasFocus = false;
14781 this.cancelBtn.hide();
14782 this.trigger.show();
14785 this.tickableInputEl().dom.value = '';
14786 this.tickableInputEl().blur();
14791 Roo.get(document).un('mousedown', this.collapseIf, this);
14792 Roo.get(document).un('mousewheel', this.collapseIf, this);
14793 if (!this.editable) {
14794 Roo.get(document).un('keydown', this.listKeyPress, this);
14796 this.fireEvent('collapse', this);
14802 collapseIf : function(e){
14803 var in_combo = e.within(this.el);
14804 var in_list = e.within(this.list);
14805 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14807 if (in_combo || in_list || is_list) {
14808 //e.stopPropagation();
14813 this.onTickableFooterButtonClick(e, false, false);
14821 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14823 expand : function(){
14825 if(this.isExpanded() || !this.hasFocus){
14829 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14830 this.list.setWidth(lw);
14836 this.restrictHeight();
14840 this.tickItems = Roo.apply([], this.item);
14843 this.cancelBtn.show();
14844 this.trigger.hide();
14847 this.tickableInputEl().focus();
14852 Roo.get(document).on('mousedown', this.collapseIf, this);
14853 Roo.get(document).on('mousewheel', this.collapseIf, this);
14854 if (!this.editable) {
14855 Roo.get(document).on('keydown', this.listKeyPress, this);
14858 this.fireEvent('expand', this);
14862 // Implements the default empty TriggerField.onTriggerClick function
14863 onTriggerClick : function(e)
14865 Roo.log('trigger click');
14867 if(this.disabled || !this.triggerList){
14872 this.loadNext = false;
14874 if(this.isExpanded()){
14876 if (!this.blockFocus) {
14877 this.inputEl().focus();
14881 this.hasFocus = true;
14882 if(this.triggerAction == 'all') {
14883 this.doQuery(this.allQuery, true);
14885 this.doQuery(this.getRawValue());
14887 if (!this.blockFocus) {
14888 this.inputEl().focus();
14893 onTickableTriggerClick : function(e)
14900 this.loadNext = false;
14901 this.hasFocus = true;
14903 if(this.triggerAction == 'all') {
14904 this.doQuery(this.allQuery, true);
14906 this.doQuery(this.getRawValue());
14910 onSearchFieldClick : function(e)
14912 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14913 this.onTickableFooterButtonClick(e, false, false);
14917 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14922 this.loadNext = false;
14923 this.hasFocus = true;
14925 if(this.triggerAction == 'all') {
14926 this.doQuery(this.allQuery, true);
14928 this.doQuery(this.getRawValue());
14932 listKeyPress : function(e)
14934 //Roo.log('listkeypress');
14935 // scroll to first matching element based on key pres..
14936 if (e.isSpecialKey()) {
14939 var k = String.fromCharCode(e.getKey()).toUpperCase();
14942 var csel = this.view.getSelectedNodes();
14943 var cselitem = false;
14945 var ix = this.view.indexOf(csel[0]);
14946 cselitem = this.store.getAt(ix);
14947 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14953 this.store.each(function(v) {
14955 // start at existing selection.
14956 if (cselitem.id == v.id) {
14962 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14963 match = this.store.indexOf(v);
14969 if (match === false) {
14970 return true; // no more action?
14973 this.view.select(match);
14974 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14975 sn.scrollIntoView(sn.dom.parentNode, false);
14978 onViewScroll : function(e, t){
14980 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){
14984 this.hasQuery = true;
14986 this.loading = this.list.select('.loading', true).first();
14988 if(this.loading === null){
14989 this.list.createChild({
14991 cls: 'loading roo-select2-more-results roo-select2-active',
14992 html: 'Loading more results...'
14995 this.loading = this.list.select('.loading', true).first();
14997 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14999 this.loading.hide();
15002 this.loading.show();
15007 this.loadNext = true;
15009 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15014 addItem : function(o)
15016 var dv = ''; // display value
15018 if (this.displayField) {
15019 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15021 // this is an error condition!!!
15022 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15029 var choice = this.choices.createChild({
15031 cls: 'roo-select2-search-choice',
15040 cls: 'roo-select2-search-choice-close fa fa-times',
15045 }, this.searchField);
15047 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15049 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15057 this.inputEl().dom.value = '';
15062 onRemoveItem : function(e, _self, o)
15064 e.preventDefault();
15066 this.lastItem = Roo.apply([], this.item);
15068 var index = this.item.indexOf(o.data) * 1;
15071 Roo.log('not this item?!');
15075 this.item.splice(index, 1);
15080 this.fireEvent('remove', this, e);
15086 syncValue : function()
15088 if(!this.item.length){
15095 Roo.each(this.item, function(i){
15096 if(_this.valueField){
15097 value.push(i[_this.valueField]);
15104 this.value = value.join(',');
15106 if(this.hiddenField){
15107 this.hiddenField.dom.value = this.value;
15110 this.store.fireEvent("datachanged", this.store);
15115 clearItem : function()
15117 if(!this.multiple){
15123 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15131 if(this.tickable && !Roo.isTouch){
15132 this.view.refresh();
15136 inputEl: function ()
15138 if(Roo.isIOS && this.useNativeIOS){
15139 return this.el.select('select.roo-ios-select', true).first();
15142 if(Roo.isTouch && this.mobileTouchView){
15143 return this.el.select('input.form-control',true).first();
15147 return this.searchField;
15150 return this.el.select('input.form-control',true).first();
15153 onTickableFooterButtonClick : function(e, btn, el)
15155 e.preventDefault();
15157 this.lastItem = Roo.apply([], this.item);
15159 if(btn && btn.name == 'cancel'){
15160 this.tickItems = Roo.apply([], this.item);
15169 Roo.each(this.tickItems, function(o){
15177 validate : function()
15179 if(this.getVisibilityEl().hasClass('hidden')){
15183 var v = this.getRawValue();
15186 v = this.getValue();
15189 if(this.disabled || this.allowBlank || v.length){
15194 this.markInvalid();
15198 tickableInputEl : function()
15200 if(!this.tickable || !this.editable){
15201 return this.inputEl();
15204 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15208 getAutoCreateTouchView : function()
15213 cls: 'form-group' //input-group
15219 type : this.inputType,
15220 cls : 'form-control x-combo-noedit',
15221 autocomplete: 'new-password',
15222 placeholder : this.placeholder || '',
15227 input.name = this.name;
15231 input.cls += ' input-' + this.size;
15234 if (this.disabled) {
15235 input.disabled = true;
15246 inputblock.cls += ' input-group';
15248 inputblock.cn.unshift({
15250 cls : 'input-group-addon input-group-prepend input-group-text',
15255 if(this.removable && !this.multiple){
15256 inputblock.cls += ' roo-removable';
15258 inputblock.cn.push({
15261 cls : 'roo-combo-removable-btn close'
15265 if(this.hasFeedback && !this.allowBlank){
15267 inputblock.cls += ' has-feedback';
15269 inputblock.cn.push({
15271 cls: 'glyphicon form-control-feedback'
15278 inputblock.cls += (this.before) ? '' : ' input-group';
15280 inputblock.cn.push({
15282 cls : 'input-group-addon input-group-append input-group-text',
15288 var ibwrap = inputblock;
15293 cls: 'roo-select2-choices',
15297 cls: 'roo-select2-search-field',
15310 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15315 cls: 'form-hidden-field'
15321 if(!this.multiple && this.showToggleBtn){
15328 if (this.caret != false) {
15331 cls: 'fa fa-' + this.caret
15338 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15343 cls: 'combobox-clear',
15357 combobox.cls += ' roo-select2-container-multi';
15360 var align = this.labelAlign || this.parentLabelAlign();
15362 if (align ==='left' && this.fieldLabel.length) {
15367 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15368 tooltip : 'This field is required'
15372 cls : 'control-label col-form-label',
15373 html : this.fieldLabel
15384 var labelCfg = cfg.cn[1];
15385 var contentCfg = cfg.cn[2];
15388 if(this.indicatorpos == 'right'){
15393 cls : 'control-label col-form-label',
15397 html : this.fieldLabel
15401 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15402 tooltip : 'This field is required'
15415 labelCfg = cfg.cn[0];
15416 contentCfg = cfg.cn[1];
15421 if(this.labelWidth > 12){
15422 labelCfg.style = "width: " + this.labelWidth + 'px';
15425 if(this.labelWidth < 13 && this.labelmd == 0){
15426 this.labelmd = this.labelWidth;
15429 if(this.labellg > 0){
15430 labelCfg.cls += ' col-lg-' + this.labellg;
15431 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15434 if(this.labelmd > 0){
15435 labelCfg.cls += ' col-md-' + this.labelmd;
15436 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15439 if(this.labelsm > 0){
15440 labelCfg.cls += ' col-sm-' + this.labelsm;
15441 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15444 if(this.labelxs > 0){
15445 labelCfg.cls += ' col-xs-' + this.labelxs;
15446 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15450 } else if ( this.fieldLabel.length) {
15454 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15455 tooltip : 'This field is required'
15459 cls : 'control-label',
15460 html : this.fieldLabel
15471 if(this.indicatorpos == 'right'){
15475 cls : 'control-label',
15476 html : this.fieldLabel,
15480 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15481 tooltip : 'This field is required'
15498 var settings = this;
15500 ['xs','sm','md','lg'].map(function(size){
15501 if (settings[size]) {
15502 cfg.cls += ' col-' + size + '-' + settings[size];
15509 initTouchView : function()
15511 this.renderTouchView();
15513 this.touchViewEl.on('scroll', function(){
15514 this.el.dom.scrollTop = 0;
15517 this.originalValue = this.getValue();
15519 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15521 this.inputEl().on("click", this.showTouchView, this);
15522 if (this.triggerEl) {
15523 this.triggerEl.on("click", this.showTouchView, this);
15527 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15528 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15530 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15532 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15533 this.store.on('load', this.onTouchViewLoad, this);
15534 this.store.on('loadexception', this.onTouchViewLoadException, this);
15536 if(this.hiddenName){
15538 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15540 this.hiddenField.dom.value =
15541 this.hiddenValue !== undefined ? this.hiddenValue :
15542 this.value !== undefined ? this.value : '';
15544 this.el.dom.removeAttribute('name');
15545 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15549 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15550 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15553 if(this.removable && !this.multiple){
15554 var close = this.closeTriggerEl();
15556 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15557 close.on('click', this.removeBtnClick, this, close);
15561 * fix the bug in Safari iOS8
15563 this.inputEl().on("focus", function(e){
15564 document.activeElement.blur();
15567 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15574 renderTouchView : function()
15576 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15577 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15579 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15580 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15582 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15583 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15584 this.touchViewBodyEl.setStyle('overflow', 'auto');
15586 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15587 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15589 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15590 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15594 showTouchView : function()
15600 this.touchViewHeaderEl.hide();
15602 if(this.modalTitle.length){
15603 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15604 this.touchViewHeaderEl.show();
15607 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15608 this.touchViewEl.show();
15610 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15612 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15613 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15615 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15617 if(this.modalTitle.length){
15618 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15621 this.touchViewBodyEl.setHeight(bodyHeight);
15625 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15627 this.touchViewEl.addClass('in');
15630 if(this._touchViewMask){
15631 Roo.get(document.body).addClass("x-body-masked");
15632 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15633 this._touchViewMask.setStyle('z-index', 10000);
15634 this._touchViewMask.addClass('show');
15637 this.doTouchViewQuery();
15641 hideTouchView : function()
15643 this.touchViewEl.removeClass('in');
15647 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15649 this.touchViewEl.setStyle('display', 'none');
15652 if(this._touchViewMask){
15653 this._touchViewMask.removeClass('show');
15654 Roo.get(document.body).removeClass("x-body-masked");
15658 setTouchViewValue : function()
15665 Roo.each(this.tickItems, function(o){
15670 this.hideTouchView();
15673 doTouchViewQuery : function()
15682 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15686 if(!this.alwaysQuery || this.mode == 'local'){
15687 this.onTouchViewLoad();
15694 onTouchViewBeforeLoad : function(combo,opts)
15700 onTouchViewLoad : function()
15702 if(this.store.getCount() < 1){
15703 this.onTouchViewEmptyResults();
15707 this.clearTouchView();
15709 var rawValue = this.getRawValue();
15711 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15713 this.tickItems = [];
15715 this.store.data.each(function(d, rowIndex){
15716 var row = this.touchViewListGroup.createChild(template);
15718 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15719 row.addClass(d.data.cls);
15722 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15725 html : d.data[this.displayField]
15728 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15729 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15732 row.removeClass('selected');
15733 if(!this.multiple && this.valueField &&
15734 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15737 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15738 row.addClass('selected');
15741 if(this.multiple && this.valueField &&
15742 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15746 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15747 this.tickItems.push(d.data);
15750 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15754 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15756 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15758 if(this.modalTitle.length){
15759 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15762 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15764 if(this.mobile_restrict_height && listHeight < bodyHeight){
15765 this.touchViewBodyEl.setHeight(listHeight);
15770 if(firstChecked && listHeight > bodyHeight){
15771 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15776 onTouchViewLoadException : function()
15778 this.hideTouchView();
15781 onTouchViewEmptyResults : function()
15783 this.clearTouchView();
15785 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15787 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15791 clearTouchView : function()
15793 this.touchViewListGroup.dom.innerHTML = '';
15796 onTouchViewClick : function(e, el, o)
15798 e.preventDefault();
15801 var rowIndex = o.rowIndex;
15803 var r = this.store.getAt(rowIndex);
15805 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15807 if(!this.multiple){
15808 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15809 c.dom.removeAttribute('checked');
15812 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15814 this.setFromData(r.data);
15816 var close = this.closeTriggerEl();
15822 this.hideTouchView();
15824 this.fireEvent('select', this, r, rowIndex);
15829 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15830 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15831 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15835 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15836 this.addItem(r.data);
15837 this.tickItems.push(r.data);
15841 getAutoCreateNativeIOS : function()
15844 cls: 'form-group' //input-group,
15849 cls : 'roo-ios-select'
15853 combobox.name = this.name;
15856 if (this.disabled) {
15857 combobox.disabled = true;
15860 var settings = this;
15862 ['xs','sm','md','lg'].map(function(size){
15863 if (settings[size]) {
15864 cfg.cls += ' col-' + size + '-' + settings[size];
15874 initIOSView : function()
15876 this.store.on('load', this.onIOSViewLoad, this);
15881 onIOSViewLoad : function()
15883 if(this.store.getCount() < 1){
15887 this.clearIOSView();
15889 if(this.allowBlank) {
15891 var default_text = '-- SELECT --';
15893 if(this.placeholder.length){
15894 default_text = this.placeholder;
15897 if(this.emptyTitle.length){
15898 default_text += ' - ' + this.emptyTitle + ' -';
15901 var opt = this.inputEl().createChild({
15904 html : default_text
15908 o[this.valueField] = 0;
15909 o[this.displayField] = default_text;
15911 this.ios_options.push({
15918 this.store.data.each(function(d, rowIndex){
15922 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15923 html = d.data[this.displayField];
15928 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15929 value = d.data[this.valueField];
15938 if(this.value == d.data[this.valueField]){
15939 option['selected'] = true;
15942 var opt = this.inputEl().createChild(option);
15944 this.ios_options.push({
15951 this.inputEl().on('change', function(){
15952 this.fireEvent('select', this);
15957 clearIOSView: function()
15959 this.inputEl().dom.innerHTML = '';
15961 this.ios_options = [];
15964 setIOSValue: function(v)
15968 if(!this.ios_options){
15972 Roo.each(this.ios_options, function(opts){
15974 opts.el.dom.removeAttribute('selected');
15976 if(opts.data[this.valueField] != v){
15980 opts.el.dom.setAttribute('selected', true);
15986 * @cfg {Boolean} grow
15990 * @cfg {Number} growMin
15994 * @cfg {Number} growMax
16003 Roo.apply(Roo.bootstrap.ComboBox, {
16007 cls: 'modal-header',
16029 cls: 'list-group-item',
16033 cls: 'roo-combobox-list-group-item-value'
16037 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16051 listItemCheckbox : {
16053 cls: 'list-group-item',
16057 cls: 'roo-combobox-list-group-item-value'
16061 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16077 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16082 cls: 'modal-footer',
16090 cls: 'col-xs-6 text-left',
16093 cls: 'btn btn-danger roo-touch-view-cancel',
16099 cls: 'col-xs-6 text-right',
16102 cls: 'btn btn-success roo-touch-view-ok',
16113 Roo.apply(Roo.bootstrap.ComboBox, {
16115 touchViewTemplate : {
16117 cls: 'modal fade roo-combobox-touch-view',
16121 cls: 'modal-dialog',
16122 style : 'position:fixed', // we have to fix position....
16126 cls: 'modal-content',
16128 Roo.bootstrap.ComboBox.header,
16129 Roo.bootstrap.ComboBox.body,
16130 Roo.bootstrap.ComboBox.footer
16139 * Ext JS Library 1.1.1
16140 * Copyright(c) 2006-2007, Ext JS, LLC.
16142 * Originally Released Under LGPL - original licence link has changed is not relivant.
16145 * <script type="text/javascript">
16150 * @extends Roo.util.Observable
16151 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16152 * This class also supports single and multi selection modes. <br>
16153 * Create a data model bound view:
16155 var store = new Roo.data.Store(...);
16157 var view = new Roo.View({
16159 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16161 singleSelect: true,
16162 selectedClass: "ydataview-selected",
16166 // listen for node click?
16167 view.on("click", function(vw, index, node, e){
16168 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16172 dataModel.load("foobar.xml");
16174 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16176 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16177 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16179 * Note: old style constructor is still suported (container, template, config)
16182 * Create a new View
16183 * @param {Object} config The config object
16186 Roo.View = function(config, depreciated_tpl, depreciated_config){
16188 this.parent = false;
16190 if (typeof(depreciated_tpl) == 'undefined') {
16191 // new way.. - universal constructor.
16192 Roo.apply(this, config);
16193 this.el = Roo.get(this.el);
16196 this.el = Roo.get(config);
16197 this.tpl = depreciated_tpl;
16198 Roo.apply(this, depreciated_config);
16200 this.wrapEl = this.el.wrap().wrap();
16201 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16204 if(typeof(this.tpl) == "string"){
16205 this.tpl = new Roo.Template(this.tpl);
16207 // support xtype ctors..
16208 this.tpl = new Roo.factory(this.tpl, Roo);
16212 this.tpl.compile();
16217 * @event beforeclick
16218 * Fires before a click is processed. Returns false to cancel the default action.
16219 * @param {Roo.View} this
16220 * @param {Number} index The index of the target node
16221 * @param {HTMLElement} node The target node
16222 * @param {Roo.EventObject} e The raw event object
16224 "beforeclick" : true,
16227 * Fires when a template node is clicked.
16228 * @param {Roo.View} this
16229 * @param {Number} index The index of the target node
16230 * @param {HTMLElement} node The target node
16231 * @param {Roo.EventObject} e The raw event object
16236 * Fires when a template node is double clicked.
16237 * @param {Roo.View} this
16238 * @param {Number} index The index of the target node
16239 * @param {HTMLElement} node The target node
16240 * @param {Roo.EventObject} e The raw event object
16244 * @event contextmenu
16245 * Fires when a template node is right clicked.
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 "contextmenu" : true,
16253 * @event selectionchange
16254 * Fires when the selected nodes change.
16255 * @param {Roo.View} this
16256 * @param {Array} selections Array of the selected nodes
16258 "selectionchange" : true,
16261 * @event beforeselect
16262 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16263 * @param {Roo.View} this
16264 * @param {HTMLElement} node The node to be selected
16265 * @param {Array} selections Array of currently selected nodes
16267 "beforeselect" : true,
16269 * @event preparedata
16270 * Fires on every row to render, to allow you to change the data.
16271 * @param {Roo.View} this
16272 * @param {Object} data to be rendered (change this)
16274 "preparedata" : true
16282 "click": this.onClick,
16283 "dblclick": this.onDblClick,
16284 "contextmenu": this.onContextMenu,
16288 this.selections = [];
16290 this.cmp = new Roo.CompositeElementLite([]);
16292 this.store = Roo.factory(this.store, Roo.data);
16293 this.setStore(this.store, true);
16296 if ( this.footer && this.footer.xtype) {
16298 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16300 this.footer.dataSource = this.store;
16301 this.footer.container = fctr;
16302 this.footer = Roo.factory(this.footer, Roo);
16303 fctr.insertFirst(this.el);
16305 // this is a bit insane - as the paging toolbar seems to detach the el..
16306 // dom.parentNode.parentNode.parentNode
16307 // they get detached?
16311 Roo.View.superclass.constructor.call(this);
16316 Roo.extend(Roo.View, Roo.util.Observable, {
16319 * @cfg {Roo.data.Store} store Data store to load data from.
16324 * @cfg {String|Roo.Element} el The container element.
16329 * @cfg {String|Roo.Template} tpl The template used by this View
16333 * @cfg {String} dataName the named area of the template to use as the data area
16334 * Works with domtemplates roo-name="name"
16338 * @cfg {String} selectedClass The css class to add to selected nodes
16340 selectedClass : "x-view-selected",
16342 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16347 * @cfg {String} text to display on mask (default Loading)
16351 * @cfg {Boolean} multiSelect Allow multiple selection
16353 multiSelect : false,
16355 * @cfg {Boolean} singleSelect Allow single selection
16357 singleSelect: false,
16360 * @cfg {Boolean} toggleSelect - selecting
16362 toggleSelect : false,
16365 * @cfg {Boolean} tickable - selecting
16370 * Returns the element this view is bound to.
16371 * @return {Roo.Element}
16373 getEl : function(){
16374 return this.wrapEl;
16380 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16382 refresh : function(){
16383 //Roo.log('refresh');
16386 // if we are using something like 'domtemplate', then
16387 // the what gets used is:
16388 // t.applySubtemplate(NAME, data, wrapping data..)
16389 // the outer template then get' applied with
16390 // the store 'extra data'
16391 // and the body get's added to the
16392 // roo-name="data" node?
16393 // <span class='roo-tpl-{name}'></span> ?????
16397 this.clearSelections();
16398 this.el.update("");
16400 var records = this.store.getRange();
16401 if(records.length < 1) {
16403 // is this valid?? = should it render a template??
16405 this.el.update(this.emptyText);
16409 if (this.dataName) {
16410 this.el.update(t.apply(this.store.meta)); //????
16411 el = this.el.child('.roo-tpl-' + this.dataName);
16414 for(var i = 0, len = records.length; i < len; i++){
16415 var data = this.prepareData(records[i].data, i, records[i]);
16416 this.fireEvent("preparedata", this, data, i, records[i]);
16418 var d = Roo.apply({}, data);
16421 Roo.apply(d, {'roo-id' : Roo.id()});
16425 Roo.each(this.parent.item, function(item){
16426 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16429 Roo.apply(d, {'roo-data-checked' : 'checked'});
16433 html[html.length] = Roo.util.Format.trim(
16435 t.applySubtemplate(this.dataName, d, this.store.meta) :
16442 el.update(html.join(""));
16443 this.nodes = el.dom.childNodes;
16444 this.updateIndexes(0);
16449 * Function to override to reformat the data that is sent to
16450 * the template for each node.
16451 * DEPRICATED - use the preparedata event handler.
16452 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16453 * a JSON object for an UpdateManager bound view).
16455 prepareData : function(data, index, record)
16457 this.fireEvent("preparedata", this, data, index, record);
16461 onUpdate : function(ds, record){
16462 // Roo.log('on update');
16463 this.clearSelections();
16464 var index = this.store.indexOf(record);
16465 var n = this.nodes[index];
16466 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16467 n.parentNode.removeChild(n);
16468 this.updateIndexes(index, index);
16474 onAdd : function(ds, records, index)
16476 //Roo.log(['on Add', ds, records, index] );
16477 this.clearSelections();
16478 if(this.nodes.length == 0){
16482 var n = this.nodes[index];
16483 for(var i = 0, len = records.length; i < len; i++){
16484 var d = this.prepareData(records[i].data, i, records[i]);
16486 this.tpl.insertBefore(n, d);
16489 this.tpl.append(this.el, d);
16492 this.updateIndexes(index);
16495 onRemove : function(ds, record, index){
16496 // Roo.log('onRemove');
16497 this.clearSelections();
16498 var el = this.dataName ?
16499 this.el.child('.roo-tpl-' + this.dataName) :
16502 el.dom.removeChild(this.nodes[index]);
16503 this.updateIndexes(index);
16507 * Refresh an individual node.
16508 * @param {Number} index
16510 refreshNode : function(index){
16511 this.onUpdate(this.store, this.store.getAt(index));
16514 updateIndexes : function(startIndex, endIndex){
16515 var ns = this.nodes;
16516 startIndex = startIndex || 0;
16517 endIndex = endIndex || ns.length - 1;
16518 for(var i = startIndex; i <= endIndex; i++){
16519 ns[i].nodeIndex = i;
16524 * Changes the data store this view uses and refresh the view.
16525 * @param {Store} store
16527 setStore : function(store, initial){
16528 if(!initial && this.store){
16529 this.store.un("datachanged", this.refresh);
16530 this.store.un("add", this.onAdd);
16531 this.store.un("remove", this.onRemove);
16532 this.store.un("update", this.onUpdate);
16533 this.store.un("clear", this.refresh);
16534 this.store.un("beforeload", this.onBeforeLoad);
16535 this.store.un("load", this.onLoad);
16536 this.store.un("loadexception", this.onLoad);
16540 store.on("datachanged", this.refresh, this);
16541 store.on("add", this.onAdd, this);
16542 store.on("remove", this.onRemove, this);
16543 store.on("update", this.onUpdate, this);
16544 store.on("clear", this.refresh, this);
16545 store.on("beforeload", this.onBeforeLoad, this);
16546 store.on("load", this.onLoad, this);
16547 store.on("loadexception", this.onLoad, this);
16555 * onbeforeLoad - masks the loading area.
16558 onBeforeLoad : function(store,opts)
16560 //Roo.log('onBeforeLoad');
16562 this.el.update("");
16564 this.el.mask(this.mask ? this.mask : "Loading" );
16566 onLoad : function ()
16573 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16574 * @param {HTMLElement} node
16575 * @return {HTMLElement} The template node
16577 findItemFromChild : function(node){
16578 var el = this.dataName ?
16579 this.el.child('.roo-tpl-' + this.dataName,true) :
16582 if(!node || node.parentNode == el){
16585 var p = node.parentNode;
16586 while(p && p != el){
16587 if(p.parentNode == el){
16596 onClick : function(e){
16597 var item = this.findItemFromChild(e.getTarget());
16599 var index = this.indexOf(item);
16600 if(this.onItemClick(item, index, e) !== false){
16601 this.fireEvent("click", this, index, item, e);
16604 this.clearSelections();
16609 onContextMenu : function(e){
16610 var item = this.findItemFromChild(e.getTarget());
16612 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16617 onDblClick : function(e){
16618 var item = this.findItemFromChild(e.getTarget());
16620 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16624 onItemClick : function(item, index, e)
16626 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16629 if (this.toggleSelect) {
16630 var m = this.isSelected(item) ? 'unselect' : 'select';
16633 _t[m](item, true, false);
16636 if(this.multiSelect || this.singleSelect){
16637 if(this.multiSelect && e.shiftKey && this.lastSelection){
16638 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16640 this.select(item, this.multiSelect && e.ctrlKey);
16641 this.lastSelection = item;
16644 if(!this.tickable){
16645 e.preventDefault();
16653 * Get the number of selected nodes.
16656 getSelectionCount : function(){
16657 return this.selections.length;
16661 * Get the currently selected nodes.
16662 * @return {Array} An array of HTMLElements
16664 getSelectedNodes : function(){
16665 return this.selections;
16669 * Get the indexes of the selected nodes.
16672 getSelectedIndexes : function(){
16673 var indexes = [], s = this.selections;
16674 for(var i = 0, len = s.length; i < len; i++){
16675 indexes.push(s[i].nodeIndex);
16681 * Clear all selections
16682 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16684 clearSelections : function(suppressEvent){
16685 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16686 this.cmp.elements = this.selections;
16687 this.cmp.removeClass(this.selectedClass);
16688 this.selections = [];
16689 if(!suppressEvent){
16690 this.fireEvent("selectionchange", this, this.selections);
16696 * Returns true if the passed node is selected
16697 * @param {HTMLElement/Number} node The node or node index
16698 * @return {Boolean}
16700 isSelected : function(node){
16701 var s = this.selections;
16705 node = this.getNode(node);
16706 return s.indexOf(node) !== -1;
16711 * @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
16712 * @param {Boolean} keepExisting (optional) true to keep existing selections
16713 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16715 select : function(nodeInfo, keepExisting, suppressEvent){
16716 if(nodeInfo instanceof Array){
16718 this.clearSelections(true);
16720 for(var i = 0, len = nodeInfo.length; i < len; i++){
16721 this.select(nodeInfo[i], true, true);
16725 var node = this.getNode(nodeInfo);
16726 if(!node || this.isSelected(node)){
16727 return; // already selected.
16730 this.clearSelections(true);
16733 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16734 Roo.fly(node).addClass(this.selectedClass);
16735 this.selections.push(node);
16736 if(!suppressEvent){
16737 this.fireEvent("selectionchange", this, this.selections);
16745 * @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
16746 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16747 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16749 unselect : function(nodeInfo, keepExisting, suppressEvent)
16751 if(nodeInfo instanceof Array){
16752 Roo.each(this.selections, function(s) {
16753 this.unselect(s, nodeInfo);
16757 var node = this.getNode(nodeInfo);
16758 if(!node || !this.isSelected(node)){
16759 //Roo.log("not selected");
16760 return; // not selected.
16764 Roo.each(this.selections, function(s) {
16766 Roo.fly(node).removeClass(this.selectedClass);
16773 this.selections= ns;
16774 this.fireEvent("selectionchange", this, this.selections);
16778 * Gets a template node.
16779 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16780 * @return {HTMLElement} The node or null if it wasn't found
16782 getNode : function(nodeInfo){
16783 if(typeof nodeInfo == "string"){
16784 return document.getElementById(nodeInfo);
16785 }else if(typeof nodeInfo == "number"){
16786 return this.nodes[nodeInfo];
16792 * Gets a range template nodes.
16793 * @param {Number} startIndex
16794 * @param {Number} endIndex
16795 * @return {Array} An array of nodes
16797 getNodes : function(start, end){
16798 var ns = this.nodes;
16799 start = start || 0;
16800 end = typeof end == "undefined" ? ns.length - 1 : end;
16803 for(var i = start; i <= end; i++){
16807 for(var i = start; i >= end; i--){
16815 * Finds the index of the passed node
16816 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16817 * @return {Number} The index of the node or -1
16819 indexOf : function(node){
16820 node = this.getNode(node);
16821 if(typeof node.nodeIndex == "number"){
16822 return node.nodeIndex;
16824 var ns = this.nodes;
16825 for(var i = 0, len = ns.length; i < len; i++){
16836 * based on jquery fullcalendar
16840 Roo.bootstrap = Roo.bootstrap || {};
16842 * @class Roo.bootstrap.Calendar
16843 * @extends Roo.bootstrap.Component
16844 * Bootstrap Calendar class
16845 * @cfg {Boolean} loadMask (true|false) default false
16846 * @cfg {Object} header generate the user specific header of the calendar, default false
16849 * Create a new Container
16850 * @param {Object} config The config object
16855 Roo.bootstrap.Calendar = function(config){
16856 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16860 * Fires when a date is selected
16861 * @param {DatePicker} this
16862 * @param {Date} date The selected date
16866 * @event monthchange
16867 * Fires when the displayed month changes
16868 * @param {DatePicker} this
16869 * @param {Date} date The selected month
16871 'monthchange': true,
16873 * @event evententer
16874 * Fires when mouse over an event
16875 * @param {Calendar} this
16876 * @param {event} Event
16878 'evententer': true,
16880 * @event eventleave
16881 * Fires when the mouse leaves an
16882 * @param {Calendar} this
16885 'eventleave': true,
16887 * @event eventclick
16888 * Fires when the mouse click an
16889 * @param {Calendar} this
16898 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16901 * @cfg {Number} startDay
16902 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16910 getAutoCreate : function(){
16913 var fc_button = function(name, corner, style, content ) {
16914 return Roo.apply({},{
16916 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16918 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16921 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16932 style : 'width:100%',
16939 cls : 'fc-header-left',
16941 fc_button('prev', 'left', 'arrow', '‹' ),
16942 fc_button('next', 'right', 'arrow', '›' ),
16943 { tag: 'span', cls: 'fc-header-space' },
16944 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16952 cls : 'fc-header-center',
16956 cls: 'fc-header-title',
16959 html : 'month / year'
16967 cls : 'fc-header-right',
16969 /* fc_button('month', 'left', '', 'month' ),
16970 fc_button('week', '', '', 'week' ),
16971 fc_button('day', 'right', '', 'day' )
16983 header = this.header;
16986 var cal_heads = function() {
16988 // fixme - handle this.
16990 for (var i =0; i < Date.dayNames.length; i++) {
16991 var d = Date.dayNames[i];
16994 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16995 html : d.substring(0,3)
16999 ret[0].cls += ' fc-first';
17000 ret[6].cls += ' fc-last';
17003 var cal_cell = function(n) {
17006 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17011 cls: 'fc-day-number',
17015 cls: 'fc-day-content',
17019 style: 'position: relative;' // height: 17px;
17031 var cal_rows = function() {
17034 for (var r = 0; r < 6; r++) {
17041 for (var i =0; i < Date.dayNames.length; i++) {
17042 var d = Date.dayNames[i];
17043 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17046 row.cn[0].cls+=' fc-first';
17047 row.cn[0].cn[0].style = 'min-height:90px';
17048 row.cn[6].cls+=' fc-last';
17052 ret[0].cls += ' fc-first';
17053 ret[4].cls += ' fc-prev-last';
17054 ret[5].cls += ' fc-last';
17061 cls: 'fc-border-separate',
17062 style : 'width:100%',
17070 cls : 'fc-first fc-last',
17088 cls : 'fc-content',
17089 style : "position: relative;",
17092 cls : 'fc-view fc-view-month fc-grid',
17093 style : 'position: relative',
17094 unselectable : 'on',
17097 cls : 'fc-event-container',
17098 style : 'position:absolute;z-index:8;top:0;left:0;'
17116 initEvents : function()
17119 throw "can not find store for calendar";
17125 style: "text-align:center",
17129 style: "background-color:white;width:50%;margin:250 auto",
17133 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17144 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17146 var size = this.el.select('.fc-content', true).first().getSize();
17147 this.maskEl.setSize(size.width, size.height);
17148 this.maskEl.enableDisplayMode("block");
17149 if(!this.loadMask){
17150 this.maskEl.hide();
17153 this.store = Roo.factory(this.store, Roo.data);
17154 this.store.on('load', this.onLoad, this);
17155 this.store.on('beforeload', this.onBeforeLoad, this);
17159 this.cells = this.el.select('.fc-day',true);
17160 //Roo.log(this.cells);
17161 this.textNodes = this.el.query('.fc-day-number');
17162 this.cells.addClassOnOver('fc-state-hover');
17164 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17165 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17166 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17167 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17169 this.on('monthchange', this.onMonthChange, this);
17171 this.update(new Date().clearTime());
17174 resize : function() {
17175 var sz = this.el.getSize();
17177 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17178 this.el.select('.fc-day-content div',true).setHeight(34);
17183 showPrevMonth : function(e){
17184 this.update(this.activeDate.add("mo", -1));
17186 showToday : function(e){
17187 this.update(new Date().clearTime());
17190 showNextMonth : function(e){
17191 this.update(this.activeDate.add("mo", 1));
17195 showPrevYear : function(){
17196 this.update(this.activeDate.add("y", -1));
17200 showNextYear : function(){
17201 this.update(this.activeDate.add("y", 1));
17206 update : function(date)
17208 var vd = this.activeDate;
17209 this.activeDate = date;
17210 // if(vd && this.el){
17211 // var t = date.getTime();
17212 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17213 // Roo.log('using add remove');
17215 // this.fireEvent('monthchange', this, date);
17217 // this.cells.removeClass("fc-state-highlight");
17218 // this.cells.each(function(c){
17219 // if(c.dateValue == t){
17220 // c.addClass("fc-state-highlight");
17221 // setTimeout(function(){
17222 // try{c.dom.firstChild.focus();}catch(e){}
17232 var days = date.getDaysInMonth();
17234 var firstOfMonth = date.getFirstDateOfMonth();
17235 var startingPos = firstOfMonth.getDay()-this.startDay;
17237 if(startingPos < this.startDay){
17241 var pm = date.add(Date.MONTH, -1);
17242 var prevStart = pm.getDaysInMonth()-startingPos;
17244 this.cells = this.el.select('.fc-day',true);
17245 this.textNodes = this.el.query('.fc-day-number');
17246 this.cells.addClassOnOver('fc-state-hover');
17248 var cells = this.cells.elements;
17249 var textEls = this.textNodes;
17251 Roo.each(cells, function(cell){
17252 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17255 days += startingPos;
17257 // convert everything to numbers so it's fast
17258 var day = 86400000;
17259 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17262 //Roo.log(prevStart);
17264 var today = new Date().clearTime().getTime();
17265 var sel = date.clearTime().getTime();
17266 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17267 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17268 var ddMatch = this.disabledDatesRE;
17269 var ddText = this.disabledDatesText;
17270 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17271 var ddaysText = this.disabledDaysText;
17272 var format = this.format;
17274 var setCellClass = function(cal, cell){
17278 //Roo.log('set Cell Class');
17280 var t = d.getTime();
17284 cell.dateValue = t;
17286 cell.className += " fc-today";
17287 cell.className += " fc-state-highlight";
17288 cell.title = cal.todayText;
17291 // disable highlight in other month..
17292 //cell.className += " fc-state-highlight";
17297 cell.className = " fc-state-disabled";
17298 cell.title = cal.minText;
17302 cell.className = " fc-state-disabled";
17303 cell.title = cal.maxText;
17307 if(ddays.indexOf(d.getDay()) != -1){
17308 cell.title = ddaysText;
17309 cell.className = " fc-state-disabled";
17312 if(ddMatch && format){
17313 var fvalue = d.dateFormat(format);
17314 if(ddMatch.test(fvalue)){
17315 cell.title = ddText.replace("%0", fvalue);
17316 cell.className = " fc-state-disabled";
17320 if (!cell.initialClassName) {
17321 cell.initialClassName = cell.dom.className;
17324 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17329 for(; i < startingPos; i++) {
17330 textEls[i].innerHTML = (++prevStart);
17331 d.setDate(d.getDate()+1);
17333 cells[i].className = "fc-past fc-other-month";
17334 setCellClass(this, cells[i]);
17339 for(; i < days; i++){
17340 intDay = i - startingPos + 1;
17341 textEls[i].innerHTML = (intDay);
17342 d.setDate(d.getDate()+1);
17344 cells[i].className = ''; // "x-date-active";
17345 setCellClass(this, cells[i]);
17349 for(; i < 42; i++) {
17350 textEls[i].innerHTML = (++extraDays);
17351 d.setDate(d.getDate()+1);
17353 cells[i].className = "fc-future fc-other-month";
17354 setCellClass(this, cells[i]);
17357 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17359 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17361 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17362 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17364 if(totalRows != 6){
17365 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17366 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17369 this.fireEvent('monthchange', this, date);
17373 if(!this.internalRender){
17374 var main = this.el.dom.firstChild;
17375 var w = main.offsetWidth;
17376 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17377 Roo.fly(main).setWidth(w);
17378 this.internalRender = true;
17379 // opera does not respect the auto grow header center column
17380 // then, after it gets a width opera refuses to recalculate
17381 // without a second pass
17382 if(Roo.isOpera && !this.secondPass){
17383 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17384 this.secondPass = true;
17385 this.update.defer(10, this, [date]);
17392 findCell : function(dt) {
17393 dt = dt.clearTime().getTime();
17395 this.cells.each(function(c){
17396 //Roo.log("check " +c.dateValue + '?=' + dt);
17397 if(c.dateValue == dt){
17407 findCells : function(ev) {
17408 var s = ev.start.clone().clearTime().getTime();
17410 var e= ev.end.clone().clearTime().getTime();
17413 this.cells.each(function(c){
17414 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17416 if(c.dateValue > e){
17419 if(c.dateValue < s){
17428 // findBestRow: function(cells)
17432 // for (var i =0 ; i < cells.length;i++) {
17433 // ret = Math.max(cells[i].rows || 0,ret);
17440 addItem : function(ev)
17442 // look for vertical location slot in
17443 var cells = this.findCells(ev);
17445 // ev.row = this.findBestRow(cells);
17447 // work out the location.
17451 for(var i =0; i < cells.length; i++) {
17453 cells[i].row = cells[0].row;
17456 cells[i].row = cells[i].row + 1;
17466 if (crow.start.getY() == cells[i].getY()) {
17468 crow.end = cells[i];
17485 cells[0].events.push(ev);
17487 this.calevents.push(ev);
17490 clearEvents: function() {
17492 if(!this.calevents){
17496 Roo.each(this.cells.elements, function(c){
17502 Roo.each(this.calevents, function(e) {
17503 Roo.each(e.els, function(el) {
17504 el.un('mouseenter' ,this.onEventEnter, this);
17505 el.un('mouseleave' ,this.onEventLeave, this);
17510 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17516 renderEvents: function()
17520 this.cells.each(function(c) {
17529 if(c.row != c.events.length){
17530 r = 4 - (4 - (c.row - c.events.length));
17533 c.events = ev.slice(0, r);
17534 c.more = ev.slice(r);
17536 if(c.more.length && c.more.length == 1){
17537 c.events.push(c.more.pop());
17540 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17544 this.cells.each(function(c) {
17546 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17549 for (var e = 0; e < c.events.length; e++){
17550 var ev = c.events[e];
17551 var rows = ev.rows;
17553 for(var i = 0; i < rows.length; i++) {
17555 // how many rows should it span..
17558 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17559 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17561 unselectable : "on",
17564 cls: 'fc-event-inner',
17568 // cls: 'fc-event-time',
17569 // html : cells.length > 1 ? '' : ev.time
17573 cls: 'fc-event-title',
17574 html : String.format('{0}', ev.title)
17581 cls: 'ui-resizable-handle ui-resizable-e',
17582 html : '  '
17589 cfg.cls += ' fc-event-start';
17591 if ((i+1) == rows.length) {
17592 cfg.cls += ' fc-event-end';
17595 var ctr = _this.el.select('.fc-event-container',true).first();
17596 var cg = ctr.createChild(cfg);
17598 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17599 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17601 var r = (c.more.length) ? 1 : 0;
17602 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17603 cg.setWidth(ebox.right - sbox.x -2);
17605 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17606 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17607 cg.on('click', _this.onEventClick, _this, ev);
17618 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17619 style : 'position: absolute',
17620 unselectable : "on",
17623 cls: 'fc-event-inner',
17627 cls: 'fc-event-title',
17635 cls: 'ui-resizable-handle ui-resizable-e',
17636 html : '  '
17642 var ctr = _this.el.select('.fc-event-container',true).first();
17643 var cg = ctr.createChild(cfg);
17645 var sbox = c.select('.fc-day-content',true).first().getBox();
17646 var ebox = c.select('.fc-day-content',true).first().getBox();
17648 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17649 cg.setWidth(ebox.right - sbox.x -2);
17651 cg.on('click', _this.onMoreEventClick, _this, c.more);
17661 onEventEnter: function (e, el,event,d) {
17662 this.fireEvent('evententer', this, el, event);
17665 onEventLeave: function (e, el,event,d) {
17666 this.fireEvent('eventleave', this, el, event);
17669 onEventClick: function (e, el,event,d) {
17670 this.fireEvent('eventclick', this, el, event);
17673 onMonthChange: function () {
17677 onMoreEventClick: function(e, el, more)
17681 this.calpopover.placement = 'right';
17682 this.calpopover.setTitle('More');
17684 this.calpopover.setContent('');
17686 var ctr = this.calpopover.el.select('.popover-content', true).first();
17688 Roo.each(more, function(m){
17690 cls : 'fc-event-hori fc-event-draggable',
17693 var cg = ctr.createChild(cfg);
17695 cg.on('click', _this.onEventClick, _this, m);
17698 this.calpopover.show(el);
17703 onLoad: function ()
17705 this.calevents = [];
17708 if(this.store.getCount() > 0){
17709 this.store.data.each(function(d){
17712 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17713 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17714 time : d.data.start_time,
17715 title : d.data.title,
17716 description : d.data.description,
17717 venue : d.data.venue
17722 this.renderEvents();
17724 if(this.calevents.length && this.loadMask){
17725 this.maskEl.hide();
17729 onBeforeLoad: function()
17731 this.clearEvents();
17733 this.maskEl.show();
17747 * @class Roo.bootstrap.Popover
17748 * @extends Roo.bootstrap.Component
17749 * Bootstrap Popover class
17750 * @cfg {String} html contents of the popover (or false to use children..)
17751 * @cfg {String} title of popover (or false to hide)
17752 * @cfg {String} placement how it is placed
17753 * @cfg {String} trigger click || hover (or false to trigger manually)
17754 * @cfg {String} over what (parent or false to trigger manually.)
17755 * @cfg {Number} delay - delay before showing
17758 * Create a new Popover
17759 * @param {Object} config The config object
17762 Roo.bootstrap.Popover = function(config){
17763 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17769 * After the popover show
17771 * @param {Roo.bootstrap.Popover} this
17776 * After the popover hide
17778 * @param {Roo.bootstrap.Popover} this
17784 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17786 title: 'Fill in a title',
17789 placement : 'right',
17790 trigger : 'hover', // hover
17796 can_build_overlaid : false,
17798 getChildContainer : function()
17800 return this.el.select('.popover-content',true).first();
17803 getAutoCreate : function(){
17806 cls : 'popover roo-dynamic',
17807 style: 'display:block',
17813 cls : 'popover-inner',
17817 cls: 'popover-title popover-header',
17821 cls : 'popover-content popover-body',
17832 setTitle: function(str)
17835 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17837 setContent: function(str)
17840 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17842 // as it get's added to the bottom of the page.
17843 onRender : function(ct, position)
17845 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17847 var cfg = Roo.apply({}, this.getAutoCreate());
17851 cfg.cls += ' ' + this.cls;
17854 cfg.style = this.style;
17856 //Roo.log("adding to ");
17857 this.el = Roo.get(document.body).createChild(cfg, position);
17858 // Roo.log(this.el);
17863 initEvents : function()
17865 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17866 this.el.enableDisplayMode('block');
17868 if (this.over === false) {
17871 if (this.triggers === false) {
17874 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17875 var triggers = this.trigger ? this.trigger.split(' ') : [];
17876 Roo.each(triggers, function(trigger) {
17878 if (trigger == 'click') {
17879 on_el.on('click', this.toggle, this);
17880 } else if (trigger != 'manual') {
17881 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17882 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17884 on_el.on(eventIn ,this.enter, this);
17885 on_el.on(eventOut, this.leave, this);
17896 toggle : function () {
17897 this.hoverState == 'in' ? this.leave() : this.enter();
17900 enter : function () {
17902 clearTimeout(this.timeout);
17904 this.hoverState = 'in';
17906 if (!this.delay || !this.delay.show) {
17911 this.timeout = setTimeout(function () {
17912 if (_t.hoverState == 'in') {
17915 }, this.delay.show)
17918 leave : function() {
17919 clearTimeout(this.timeout);
17921 this.hoverState = 'out';
17923 if (!this.delay || !this.delay.hide) {
17928 this.timeout = setTimeout(function () {
17929 if (_t.hoverState == 'out') {
17932 }, this.delay.hide)
17935 show : function (on_el)
17938 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17942 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17943 if (this.html !== false) {
17944 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17946 this.el.removeClass([
17947 'fade','top','bottom', 'left', 'right','in',
17948 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17950 if (!this.title.length) {
17951 this.el.select('.popover-title',true).hide();
17954 var placement = typeof this.placement == 'function' ?
17955 this.placement.call(this, this.el, on_el) :
17958 var autoToken = /\s?auto?\s?/i;
17959 var autoPlace = autoToken.test(placement);
17961 placement = placement.replace(autoToken, '') || 'top';
17965 //this.el.setXY([0,0]);
17967 this.el.dom.style.display='block';
17968 this.el.addClass(placement);
17970 //this.el.appendTo(on_el);
17972 var p = this.getPosition();
17973 var box = this.el.getBox();
17978 var align = Roo.bootstrap.Popover.alignment[placement];
17981 this.el.alignTo(on_el, align[0],align[1]);
17982 //var arrow = this.el.select('.arrow',true).first();
17983 //arrow.set(align[2],
17985 this.el.addClass('in');
17988 if (this.el.hasClass('fade')) {
17992 this.hoverState = 'in';
17994 this.fireEvent('show', this);
17999 this.el.setXY([0,0]);
18000 this.el.removeClass('in');
18002 this.hoverState = null;
18004 this.fireEvent('hide', this);
18009 Roo.bootstrap.Popover.alignment = {
18010 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18011 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18012 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18013 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18024 * @class Roo.bootstrap.Progress
18025 * @extends Roo.bootstrap.Component
18026 * Bootstrap Progress class
18027 * @cfg {Boolean} striped striped of the progress bar
18028 * @cfg {Boolean} active animated of the progress bar
18032 * Create a new Progress
18033 * @param {Object} config The config object
18036 Roo.bootstrap.Progress = function(config){
18037 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18040 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18045 getAutoCreate : function(){
18053 cfg.cls += ' progress-striped';
18057 cfg.cls += ' active';
18076 * @class Roo.bootstrap.ProgressBar
18077 * @extends Roo.bootstrap.Component
18078 * Bootstrap ProgressBar class
18079 * @cfg {Number} aria_valuenow aria-value now
18080 * @cfg {Number} aria_valuemin aria-value min
18081 * @cfg {Number} aria_valuemax aria-value max
18082 * @cfg {String} label label for the progress bar
18083 * @cfg {String} panel (success | info | warning | danger )
18084 * @cfg {String} role role of the progress bar
18085 * @cfg {String} sr_only text
18089 * Create a new ProgressBar
18090 * @param {Object} config The config object
18093 Roo.bootstrap.ProgressBar = function(config){
18094 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18097 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18101 aria_valuemax : 100,
18107 getAutoCreate : function()
18112 cls: 'progress-bar',
18113 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18125 cfg.role = this.role;
18128 if(this.aria_valuenow){
18129 cfg['aria-valuenow'] = this.aria_valuenow;
18132 if(this.aria_valuemin){
18133 cfg['aria-valuemin'] = this.aria_valuemin;
18136 if(this.aria_valuemax){
18137 cfg['aria-valuemax'] = this.aria_valuemax;
18140 if(this.label && !this.sr_only){
18141 cfg.html = this.label;
18145 cfg.cls += ' progress-bar-' + this.panel;
18151 update : function(aria_valuenow)
18153 this.aria_valuenow = aria_valuenow;
18155 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18170 * @class Roo.bootstrap.TabGroup
18171 * @extends Roo.bootstrap.Column
18172 * Bootstrap Column class
18173 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18174 * @cfg {Boolean} carousel true to make the group behave like a carousel
18175 * @cfg {Boolean} bullets show bullets for the panels
18176 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18177 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18178 * @cfg {Boolean} showarrow (true|false) show arrow default true
18181 * Create a new TabGroup
18182 * @param {Object} config The config object
18185 Roo.bootstrap.TabGroup = function(config){
18186 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18188 this.navId = Roo.id();
18191 Roo.bootstrap.TabGroup.register(this);
18195 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18198 transition : false,
18203 slideOnTouch : false,
18206 getAutoCreate : function()
18208 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18210 cfg.cls += ' tab-content';
18212 if (this.carousel) {
18213 cfg.cls += ' carousel slide';
18216 cls : 'carousel-inner',
18220 if(this.bullets && !Roo.isTouch){
18223 cls : 'carousel-bullets',
18227 if(this.bullets_cls){
18228 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18235 cfg.cn[0].cn.push(bullets);
18238 if(this.showarrow){
18239 cfg.cn[0].cn.push({
18241 class : 'carousel-arrow',
18245 class : 'carousel-prev',
18249 class : 'fa fa-chevron-left'
18255 class : 'carousel-next',
18259 class : 'fa fa-chevron-right'
18272 initEvents: function()
18274 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18275 // this.el.on("touchstart", this.onTouchStart, this);
18278 if(this.autoslide){
18281 this.slideFn = window.setInterval(function() {
18282 _this.showPanelNext();
18286 if(this.showarrow){
18287 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18288 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18294 // onTouchStart : function(e, el, o)
18296 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18300 // this.showPanelNext();
18304 getChildContainer : function()
18306 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18310 * register a Navigation item
18311 * @param {Roo.bootstrap.NavItem} the navitem to add
18313 register : function(item)
18315 this.tabs.push( item);
18316 item.navId = this.navId; // not really needed..
18321 getActivePanel : function()
18324 Roo.each(this.tabs, function(t) {
18334 getPanelByName : function(n)
18337 Roo.each(this.tabs, function(t) {
18338 if (t.tabId == n) {
18346 indexOfPanel : function(p)
18349 Roo.each(this.tabs, function(t,i) {
18350 if (t.tabId == p.tabId) {
18359 * show a specific panel
18360 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18361 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18363 showPanel : function (pan)
18365 if(this.transition || typeof(pan) == 'undefined'){
18366 Roo.log("waiting for the transitionend");
18370 if (typeof(pan) == 'number') {
18371 pan = this.tabs[pan];
18374 if (typeof(pan) == 'string') {
18375 pan = this.getPanelByName(pan);
18378 var cur = this.getActivePanel();
18381 Roo.log('pan or acitve pan is undefined');
18385 if (pan.tabId == this.getActivePanel().tabId) {
18389 if (false === cur.fireEvent('beforedeactivate')) {
18393 if(this.bullets > 0 && !Roo.isTouch){
18394 this.setActiveBullet(this.indexOfPanel(pan));
18397 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18399 //class="carousel-item carousel-item-next carousel-item-left"
18401 this.transition = true;
18402 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18403 var lr = dir == 'next' ? 'left' : 'right';
18404 pan.el.addClass(dir); // or prev
18405 pan.el.addClass('carousel-item-' + dir); // or prev
18406 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18407 cur.el.addClass(lr); // or right
18408 pan.el.addClass(lr);
18409 cur.el.addClass('carousel-item-' +lr); // or right
18410 pan.el.addClass('carousel-item-' +lr);
18414 cur.el.on('transitionend', function() {
18415 Roo.log("trans end?");
18417 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18418 pan.setActive(true);
18420 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18421 cur.setActive(false);
18423 _this.transition = false;
18425 }, this, { single: true } );
18430 cur.setActive(false);
18431 pan.setActive(true);
18436 showPanelNext : function()
18438 var i = this.indexOfPanel(this.getActivePanel());
18440 if (i >= this.tabs.length - 1 && !this.autoslide) {
18444 if (i >= this.tabs.length - 1 && this.autoslide) {
18448 this.showPanel(this.tabs[i+1]);
18451 showPanelPrev : function()
18453 var i = this.indexOfPanel(this.getActivePanel());
18455 if (i < 1 && !this.autoslide) {
18459 if (i < 1 && this.autoslide) {
18460 i = this.tabs.length;
18463 this.showPanel(this.tabs[i-1]);
18467 addBullet: function()
18469 if(!this.bullets || Roo.isTouch){
18472 var ctr = this.el.select('.carousel-bullets',true).first();
18473 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18474 var bullet = ctr.createChild({
18475 cls : 'bullet bullet-' + i
18476 },ctr.dom.lastChild);
18481 bullet.on('click', (function(e, el, o, ii, t){
18483 e.preventDefault();
18485 this.showPanel(ii);
18487 if(this.autoslide && this.slideFn){
18488 clearInterval(this.slideFn);
18489 this.slideFn = window.setInterval(function() {
18490 _this.showPanelNext();
18494 }).createDelegate(this, [i, bullet], true));
18499 setActiveBullet : function(i)
18505 Roo.each(this.el.select('.bullet', true).elements, function(el){
18506 el.removeClass('selected');
18509 var bullet = this.el.select('.bullet-' + i, true).first();
18515 bullet.addClass('selected');
18526 Roo.apply(Roo.bootstrap.TabGroup, {
18530 * register a Navigation Group
18531 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18533 register : function(navgrp)
18535 this.groups[navgrp.navId] = navgrp;
18539 * fetch a Navigation Group based on the navigation ID
18540 * if one does not exist , it will get created.
18541 * @param {string} the navgroup to add
18542 * @returns {Roo.bootstrap.NavGroup} the navgroup
18544 get: function(navId) {
18545 if (typeof(this.groups[navId]) == 'undefined') {
18546 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18548 return this.groups[navId] ;
18563 * @class Roo.bootstrap.TabPanel
18564 * @extends Roo.bootstrap.Component
18565 * Bootstrap TabPanel class
18566 * @cfg {Boolean} active panel active
18567 * @cfg {String} html panel content
18568 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18569 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18570 * @cfg {String} href click to link..
18574 * Create a new TabPanel
18575 * @param {Object} config The config object
18578 Roo.bootstrap.TabPanel = function(config){
18579 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18583 * Fires when the active status changes
18584 * @param {Roo.bootstrap.TabPanel} this
18585 * @param {Boolean} state the new state
18590 * @event beforedeactivate
18591 * Fires before a tab is de-activated - can be used to do validation on a form.
18592 * @param {Roo.bootstrap.TabPanel} this
18593 * @return {Boolean} false if there is an error
18596 'beforedeactivate': true
18599 this.tabId = this.tabId || Roo.id();
18603 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18611 getAutoCreate : function(){
18616 // item is needed for carousel - not sure if it has any effect otherwise
18617 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18618 html: this.html || ''
18622 cfg.cls += ' active';
18626 cfg.tabId = this.tabId;
18634 initEvents: function()
18636 var p = this.parent();
18638 this.navId = this.navId || p.navId;
18640 if (typeof(this.navId) != 'undefined') {
18641 // not really needed.. but just in case.. parent should be a NavGroup.
18642 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18646 var i = tg.tabs.length - 1;
18648 if(this.active && tg.bullets > 0 && i < tg.bullets){
18649 tg.setActiveBullet(i);
18653 this.el.on('click', this.onClick, this);
18656 this.el.on("touchstart", this.onTouchStart, this);
18657 this.el.on("touchmove", this.onTouchMove, this);
18658 this.el.on("touchend", this.onTouchEnd, this);
18663 onRender : function(ct, position)
18665 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18668 setActive : function(state)
18670 Roo.log("panel - set active " + this.tabId + "=" + state);
18672 this.active = state;
18674 this.el.removeClass('active');
18676 } else if (!this.el.hasClass('active')) {
18677 this.el.addClass('active');
18680 this.fireEvent('changed', this, state);
18683 onClick : function(e)
18685 e.preventDefault();
18687 if(!this.href.length){
18691 window.location.href = this.href;
18700 onTouchStart : function(e)
18702 this.swiping = false;
18704 this.startX = e.browserEvent.touches[0].clientX;
18705 this.startY = e.browserEvent.touches[0].clientY;
18708 onTouchMove : function(e)
18710 this.swiping = true;
18712 this.endX = e.browserEvent.touches[0].clientX;
18713 this.endY = e.browserEvent.touches[0].clientY;
18716 onTouchEnd : function(e)
18723 var tabGroup = this.parent();
18725 if(this.endX > this.startX){ // swiping right
18726 tabGroup.showPanelPrev();
18730 if(this.startX > this.endX){ // swiping left
18731 tabGroup.showPanelNext();
18750 * @class Roo.bootstrap.DateField
18751 * @extends Roo.bootstrap.Input
18752 * Bootstrap DateField class
18753 * @cfg {Number} weekStart default 0
18754 * @cfg {String} viewMode default empty, (months|years)
18755 * @cfg {String} minViewMode default empty, (months|years)
18756 * @cfg {Number} startDate default -Infinity
18757 * @cfg {Number} endDate default Infinity
18758 * @cfg {Boolean} todayHighlight default false
18759 * @cfg {Boolean} todayBtn default false
18760 * @cfg {Boolean} calendarWeeks default false
18761 * @cfg {Object} daysOfWeekDisabled default empty
18762 * @cfg {Boolean} singleMode default false (true | false)
18764 * @cfg {Boolean} keyboardNavigation default true
18765 * @cfg {String} language default en
18768 * Create a new DateField
18769 * @param {Object} config The config object
18772 Roo.bootstrap.DateField = function(config){
18773 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18777 * Fires when this field show.
18778 * @param {Roo.bootstrap.DateField} this
18779 * @param {Mixed} date The date value
18784 * Fires when this field hide.
18785 * @param {Roo.bootstrap.DateField} this
18786 * @param {Mixed} date The date value
18791 * Fires when select a date.
18792 * @param {Roo.bootstrap.DateField} this
18793 * @param {Mixed} date The date value
18797 * @event beforeselect
18798 * Fires when before select a date.
18799 * @param {Roo.bootstrap.DateField} this
18800 * @param {Mixed} date The date value
18802 beforeselect : true
18806 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18809 * @cfg {String} format
18810 * The default date format string which can be overriden for localization support. The format must be
18811 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18815 * @cfg {String} altFormats
18816 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18817 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18819 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18827 todayHighlight : false,
18833 keyboardNavigation: true,
18835 calendarWeeks: false,
18837 startDate: -Infinity,
18841 daysOfWeekDisabled: [],
18845 singleMode : false,
18847 UTCDate: function()
18849 return new Date(Date.UTC.apply(Date, arguments));
18852 UTCToday: function()
18854 var today = new Date();
18855 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18858 getDate: function() {
18859 var d = this.getUTCDate();
18860 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18863 getUTCDate: function() {
18867 setDate: function(d) {
18868 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18871 setUTCDate: function(d) {
18873 this.setValue(this.formatDate(this.date));
18876 onRender: function(ct, position)
18879 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18881 this.language = this.language || 'en';
18882 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18883 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18885 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18886 this.format = this.format || 'm/d/y';
18887 this.isInline = false;
18888 this.isInput = true;
18889 this.component = this.el.select('.add-on', true).first() || false;
18890 this.component = (this.component && this.component.length === 0) ? false : this.component;
18891 this.hasInput = this.component && this.inputEl().length;
18893 if (typeof(this.minViewMode === 'string')) {
18894 switch (this.minViewMode) {
18896 this.minViewMode = 1;
18899 this.minViewMode = 2;
18902 this.minViewMode = 0;
18907 if (typeof(this.viewMode === 'string')) {
18908 switch (this.viewMode) {
18921 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18923 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18925 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18927 this.picker().on('mousedown', this.onMousedown, this);
18928 this.picker().on('click', this.onClick, this);
18930 this.picker().addClass('datepicker-dropdown');
18932 this.startViewMode = this.viewMode;
18934 if(this.singleMode){
18935 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18936 v.setVisibilityMode(Roo.Element.DISPLAY);
18940 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18941 v.setStyle('width', '189px');
18945 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18946 if(!this.calendarWeeks){
18951 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18952 v.attr('colspan', function(i, val){
18953 return parseInt(val) + 1;
18958 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18960 this.setStartDate(this.startDate);
18961 this.setEndDate(this.endDate);
18963 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18970 if(this.isInline) {
18975 picker : function()
18977 return this.pickerEl;
18978 // return this.el.select('.datepicker', true).first();
18981 fillDow: function()
18983 var dowCnt = this.weekStart;
18992 if(this.calendarWeeks){
19000 while (dowCnt < this.weekStart + 7) {
19004 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19008 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19011 fillMonths: function()
19014 var months = this.picker().select('>.datepicker-months td', true).first();
19016 months.dom.innerHTML = '';
19022 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19025 months.createChild(month);
19032 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;
19034 if (this.date < this.startDate) {
19035 this.viewDate = new Date(this.startDate);
19036 } else if (this.date > this.endDate) {
19037 this.viewDate = new Date(this.endDate);
19039 this.viewDate = new Date(this.date);
19047 var d = new Date(this.viewDate),
19048 year = d.getUTCFullYear(),
19049 month = d.getUTCMonth(),
19050 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19051 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19052 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19053 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19054 currentDate = this.date && this.date.valueOf(),
19055 today = this.UTCToday();
19057 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19059 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19061 // this.picker.select('>tfoot th.today').
19062 // .text(dates[this.language].today)
19063 // .toggle(this.todayBtn !== false);
19065 this.updateNavArrows();
19068 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19070 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19072 prevMonth.setUTCDate(day);
19074 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19076 var nextMonth = new Date(prevMonth);
19078 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19080 nextMonth = nextMonth.valueOf();
19082 var fillMonths = false;
19084 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19086 while(prevMonth.valueOf() <= nextMonth) {
19089 if (prevMonth.getUTCDay() === this.weekStart) {
19091 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19099 if(this.calendarWeeks){
19100 // ISO 8601: First week contains first thursday.
19101 // ISO also states week starts on Monday, but we can be more abstract here.
19103 // Start of current week: based on weekstart/current date
19104 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19105 // Thursday of this week
19106 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19107 // First Thursday of year, year from thursday
19108 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19109 // Calendar week: ms between thursdays, div ms per day, div 7 days
19110 calWeek = (th - yth) / 864e5 / 7 + 1;
19112 fillMonths.cn.push({
19120 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19122 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19125 if (this.todayHighlight &&
19126 prevMonth.getUTCFullYear() == today.getFullYear() &&
19127 prevMonth.getUTCMonth() == today.getMonth() &&
19128 prevMonth.getUTCDate() == today.getDate()) {
19129 clsName += ' today';
19132 if (currentDate && prevMonth.valueOf() === currentDate) {
19133 clsName += ' active';
19136 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19137 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19138 clsName += ' disabled';
19141 fillMonths.cn.push({
19143 cls: 'day ' + clsName,
19144 html: prevMonth.getDate()
19147 prevMonth.setDate(prevMonth.getDate()+1);
19150 var currentYear = this.date && this.date.getUTCFullYear();
19151 var currentMonth = this.date && this.date.getUTCMonth();
19153 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19155 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19156 v.removeClass('active');
19158 if(currentYear === year && k === currentMonth){
19159 v.addClass('active');
19162 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19163 v.addClass('disabled');
19169 year = parseInt(year/10, 10) * 10;
19171 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19173 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19176 for (var i = -1; i < 11; i++) {
19177 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19179 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19187 showMode: function(dir)
19190 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19193 Roo.each(this.picker().select('>div',true).elements, function(v){
19194 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19197 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19202 if(this.isInline) {
19206 this.picker().removeClass(['bottom', 'top']);
19208 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19210 * place to the top of element!
19214 this.picker().addClass('top');
19215 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19220 this.picker().addClass('bottom');
19222 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19225 parseDate : function(value)
19227 if(!value || value instanceof Date){
19230 var v = Date.parseDate(value, this.format);
19231 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19232 v = Date.parseDate(value, 'Y-m-d');
19234 if(!v && this.altFormats){
19235 if(!this.altFormatsArray){
19236 this.altFormatsArray = this.altFormats.split("|");
19238 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19239 v = Date.parseDate(value, this.altFormatsArray[i]);
19245 formatDate : function(date, fmt)
19247 return (!date || !(date instanceof Date)) ?
19248 date : date.dateFormat(fmt || this.format);
19251 onFocus : function()
19253 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19257 onBlur : function()
19259 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19261 var d = this.inputEl().getValue();
19268 showPopup : function()
19270 this.picker().show();
19274 this.fireEvent('showpopup', this, this.date);
19277 hidePopup : function()
19279 if(this.isInline) {
19282 this.picker().hide();
19283 this.viewMode = this.startViewMode;
19286 this.fireEvent('hidepopup', this, this.date);
19290 onMousedown: function(e)
19292 e.stopPropagation();
19293 e.preventDefault();
19298 Roo.bootstrap.DateField.superclass.keyup.call(this);
19302 setValue: function(v)
19304 if(this.fireEvent('beforeselect', this, v) !== false){
19305 var d = new Date(this.parseDate(v) ).clearTime();
19307 if(isNaN(d.getTime())){
19308 this.date = this.viewDate = '';
19309 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19313 v = this.formatDate(d);
19315 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19317 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19321 this.fireEvent('select', this, this.date);
19325 getValue: function()
19327 return this.formatDate(this.date);
19330 fireKey: function(e)
19332 if (!this.picker().isVisible()){
19333 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19339 var dateChanged = false,
19341 newDate, newViewDate;
19346 e.preventDefault();
19350 if (!this.keyboardNavigation) {
19353 dir = e.keyCode == 37 ? -1 : 1;
19356 newDate = this.moveYear(this.date, dir);
19357 newViewDate = this.moveYear(this.viewDate, dir);
19358 } else if (e.shiftKey){
19359 newDate = this.moveMonth(this.date, dir);
19360 newViewDate = this.moveMonth(this.viewDate, dir);
19362 newDate = new Date(this.date);
19363 newDate.setUTCDate(this.date.getUTCDate() + dir);
19364 newViewDate = new Date(this.viewDate);
19365 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19367 if (this.dateWithinRange(newDate)){
19368 this.date = newDate;
19369 this.viewDate = newViewDate;
19370 this.setValue(this.formatDate(this.date));
19372 e.preventDefault();
19373 dateChanged = true;
19378 if (!this.keyboardNavigation) {
19381 dir = e.keyCode == 38 ? -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 * 7);
19391 newViewDate = new Date(this.viewDate);
19392 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
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;
19404 this.setValue(this.formatDate(this.date));
19406 e.preventDefault();
19409 this.setValue(this.formatDate(this.date));
19423 onClick: function(e)
19425 e.stopPropagation();
19426 e.preventDefault();
19428 var target = e.getTarget();
19430 if(target.nodeName.toLowerCase() === 'i'){
19431 target = Roo.get(target).dom.parentNode;
19434 var nodeName = target.nodeName;
19435 var className = target.className;
19436 var html = target.innerHTML;
19437 //Roo.log(nodeName);
19439 switch(nodeName.toLowerCase()) {
19441 switch(className) {
19447 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19448 switch(this.viewMode){
19450 this.viewDate = this.moveMonth(this.viewDate, dir);
19454 this.viewDate = this.moveYear(this.viewDate, dir);
19460 var date = new Date();
19461 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19463 this.setValue(this.formatDate(this.date));
19470 if (className.indexOf('disabled') < 0) {
19471 this.viewDate.setUTCDate(1);
19472 if (className.indexOf('month') > -1) {
19473 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19475 var year = parseInt(html, 10) || 0;
19476 this.viewDate.setUTCFullYear(year);
19480 if(this.singleMode){
19481 this.setValue(this.formatDate(this.viewDate));
19492 //Roo.log(className);
19493 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19494 var day = parseInt(html, 10) || 1;
19495 var year = this.viewDate.getUTCFullYear(),
19496 month = this.viewDate.getUTCMonth();
19498 if (className.indexOf('old') > -1) {
19505 } else if (className.indexOf('new') > -1) {
19513 //Roo.log([year,month,day]);
19514 this.date = this.UTCDate(year, month, day,0,0,0,0);
19515 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19517 //Roo.log(this.formatDate(this.date));
19518 this.setValue(this.formatDate(this.date));
19525 setStartDate: function(startDate)
19527 this.startDate = startDate || -Infinity;
19528 if (this.startDate !== -Infinity) {
19529 this.startDate = this.parseDate(this.startDate);
19532 this.updateNavArrows();
19535 setEndDate: function(endDate)
19537 this.endDate = endDate || Infinity;
19538 if (this.endDate !== Infinity) {
19539 this.endDate = this.parseDate(this.endDate);
19542 this.updateNavArrows();
19545 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19547 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19548 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19549 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19551 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19552 return parseInt(d, 10);
19555 this.updateNavArrows();
19558 updateNavArrows: function()
19560 if(this.singleMode){
19564 var d = new Date(this.viewDate),
19565 year = d.getUTCFullYear(),
19566 month = d.getUTCMonth();
19568 Roo.each(this.picker().select('.prev', true).elements, function(v){
19570 switch (this.viewMode) {
19573 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19579 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19586 Roo.each(this.picker().select('.next', true).elements, function(v){
19588 switch (this.viewMode) {
19591 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19597 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19605 moveMonth: function(date, dir)
19610 var new_date = new Date(date.valueOf()),
19611 day = new_date.getUTCDate(),
19612 month = new_date.getUTCMonth(),
19613 mag = Math.abs(dir),
19615 dir = dir > 0 ? 1 : -1;
19618 // If going back one month, make sure month is not current month
19619 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19621 return new_date.getUTCMonth() == month;
19623 // If going forward one month, make sure month is as expected
19624 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19626 return new_date.getUTCMonth() != new_month;
19628 new_month = month + dir;
19629 new_date.setUTCMonth(new_month);
19630 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19631 if (new_month < 0 || new_month > 11) {
19632 new_month = (new_month + 12) % 12;
19635 // For magnitudes >1, move one month at a time...
19636 for (var i=0; i<mag; i++) {
19637 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19638 new_date = this.moveMonth(new_date, dir);
19640 // ...then reset the day, keeping it in the new month
19641 new_month = new_date.getUTCMonth();
19642 new_date.setUTCDate(day);
19644 return new_month != new_date.getUTCMonth();
19647 // Common date-resetting loop -- if date is beyond end of month, make it
19650 new_date.setUTCDate(--day);
19651 new_date.setUTCMonth(new_month);
19656 moveYear: function(date, dir)
19658 return this.moveMonth(date, dir*12);
19661 dateWithinRange: function(date)
19663 return date >= this.startDate && date <= this.endDate;
19669 this.picker().remove();
19672 validateValue : function(value)
19674 if(this.getVisibilityEl().hasClass('hidden')){
19678 if(value.length < 1) {
19679 if(this.allowBlank){
19685 if(value.length < this.minLength){
19688 if(value.length > this.maxLength){
19692 var vt = Roo.form.VTypes;
19693 if(!vt[this.vtype](value, this)){
19697 if(typeof this.validator == "function"){
19698 var msg = this.validator(value);
19704 if(this.regex && !this.regex.test(value)){
19708 if(typeof(this.parseDate(value)) == 'undefined'){
19712 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19716 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19726 this.date = this.viewDate = '';
19728 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19733 Roo.apply(Roo.bootstrap.DateField, {
19744 html: '<i class="fa fa-arrow-left"/>'
19754 html: '<i class="fa fa-arrow-right"/>'
19796 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19797 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19798 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19799 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19800 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19813 navFnc: 'FullYear',
19818 navFnc: 'FullYear',
19823 Roo.apply(Roo.bootstrap.DateField, {
19827 cls: 'datepicker dropdown-menu roo-dynamic',
19831 cls: 'datepicker-days',
19835 cls: 'table-condensed',
19837 Roo.bootstrap.DateField.head,
19841 Roo.bootstrap.DateField.footer
19848 cls: 'datepicker-months',
19852 cls: 'table-condensed',
19854 Roo.bootstrap.DateField.head,
19855 Roo.bootstrap.DateField.content,
19856 Roo.bootstrap.DateField.footer
19863 cls: 'datepicker-years',
19867 cls: 'table-condensed',
19869 Roo.bootstrap.DateField.head,
19870 Roo.bootstrap.DateField.content,
19871 Roo.bootstrap.DateField.footer
19890 * @class Roo.bootstrap.TimeField
19891 * @extends Roo.bootstrap.Input
19892 * Bootstrap DateField class
19896 * Create a new TimeField
19897 * @param {Object} config The config object
19900 Roo.bootstrap.TimeField = function(config){
19901 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19905 * Fires when this field show.
19906 * @param {Roo.bootstrap.DateField} thisthis
19907 * @param {Mixed} date The date value
19912 * Fires when this field hide.
19913 * @param {Roo.bootstrap.DateField} this
19914 * @param {Mixed} date The date value
19919 * Fires when select a date.
19920 * @param {Roo.bootstrap.DateField} this
19921 * @param {Mixed} date The date value
19927 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19930 * @cfg {String} format
19931 * The default time format string which can be overriden for localization support. The format must be
19932 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19936 onRender: function(ct, position)
19939 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19941 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19943 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19945 this.pop = this.picker().select('>.datepicker-time',true).first();
19946 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19948 this.picker().on('mousedown', this.onMousedown, this);
19949 this.picker().on('click', this.onClick, this);
19951 this.picker().addClass('datepicker-dropdown');
19956 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19957 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19958 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19959 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19960 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19961 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19965 fireKey: function(e){
19966 if (!this.picker().isVisible()){
19967 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19973 e.preventDefault();
19981 this.onTogglePeriod();
19984 this.onIncrementMinutes();
19987 this.onDecrementMinutes();
19996 onClick: function(e) {
19997 e.stopPropagation();
19998 e.preventDefault();
20001 picker : function()
20003 return this.el.select('.datepicker', true).first();
20006 fillTime: function()
20008 var time = this.pop.select('tbody', true).first();
20010 time.dom.innerHTML = '';
20025 cls: 'hours-up glyphicon glyphicon-chevron-up'
20045 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20066 cls: 'timepicker-hour',
20081 cls: 'timepicker-minute',
20096 cls: 'btn btn-primary period',
20118 cls: 'hours-down glyphicon glyphicon-chevron-down'
20138 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20156 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20163 var hours = this.time.getHours();
20164 var minutes = this.time.getMinutes();
20177 hours = hours - 12;
20181 hours = '0' + hours;
20185 minutes = '0' + minutes;
20188 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20189 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20190 this.pop.select('button', true).first().dom.innerHTML = period;
20196 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20198 var cls = ['bottom'];
20200 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20207 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20212 this.picker().addClass(cls.join('-'));
20216 Roo.each(cls, function(c){
20218 _this.picker().setTop(_this.inputEl().getHeight());
20222 _this.picker().setTop(0 - _this.picker().getHeight());
20227 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20231 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20238 onFocus : function()
20240 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20244 onBlur : function()
20246 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20252 this.picker().show();
20257 this.fireEvent('show', this, this.date);
20262 this.picker().hide();
20265 this.fireEvent('hide', this, this.date);
20268 setTime : function()
20271 this.setValue(this.time.format(this.format));
20273 this.fireEvent('select', this, this.date);
20278 onMousedown: function(e){
20279 e.stopPropagation();
20280 e.preventDefault();
20283 onIncrementHours: function()
20285 Roo.log('onIncrementHours');
20286 this.time = this.time.add(Date.HOUR, 1);
20291 onDecrementHours: function()
20293 Roo.log('onDecrementHours');
20294 this.time = this.time.add(Date.HOUR, -1);
20298 onIncrementMinutes: function()
20300 Roo.log('onIncrementMinutes');
20301 this.time = this.time.add(Date.MINUTE, 1);
20305 onDecrementMinutes: function()
20307 Roo.log('onDecrementMinutes');
20308 this.time = this.time.add(Date.MINUTE, -1);
20312 onTogglePeriod: function()
20314 Roo.log('onTogglePeriod');
20315 this.time = this.time.add(Date.HOUR, 12);
20322 Roo.apply(Roo.bootstrap.TimeField, {
20352 cls: 'btn btn-info ok',
20364 Roo.apply(Roo.bootstrap.TimeField, {
20368 cls: 'datepicker dropdown-menu',
20372 cls: 'datepicker-time',
20376 cls: 'table-condensed',
20378 Roo.bootstrap.TimeField.content,
20379 Roo.bootstrap.TimeField.footer
20398 * @class Roo.bootstrap.MonthField
20399 * @extends Roo.bootstrap.Input
20400 * Bootstrap MonthField class
20402 * @cfg {String} language default en
20405 * Create a new MonthField
20406 * @param {Object} config The config object
20409 Roo.bootstrap.MonthField = function(config){
20410 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20415 * Fires when this field show.
20416 * @param {Roo.bootstrap.MonthField} this
20417 * @param {Mixed} date The date value
20422 * Fires when this field hide.
20423 * @param {Roo.bootstrap.MonthField} this
20424 * @param {Mixed} date The date value
20429 * Fires when select a date.
20430 * @param {Roo.bootstrap.MonthField} this
20431 * @param {String} oldvalue The old value
20432 * @param {String} newvalue The new value
20438 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20440 onRender: function(ct, position)
20443 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20445 this.language = this.language || 'en';
20446 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20447 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20449 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20450 this.isInline = false;
20451 this.isInput = true;
20452 this.component = this.el.select('.add-on', true).first() || false;
20453 this.component = (this.component && this.component.length === 0) ? false : this.component;
20454 this.hasInput = this.component && this.inputEL().length;
20456 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20458 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20460 this.picker().on('mousedown', this.onMousedown, this);
20461 this.picker().on('click', this.onClick, this);
20463 this.picker().addClass('datepicker-dropdown');
20465 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20466 v.setStyle('width', '189px');
20473 if(this.isInline) {
20479 setValue: function(v, suppressEvent)
20481 var o = this.getValue();
20483 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20487 if(suppressEvent !== true){
20488 this.fireEvent('select', this, o, v);
20493 getValue: function()
20498 onClick: function(e)
20500 e.stopPropagation();
20501 e.preventDefault();
20503 var target = e.getTarget();
20505 if(target.nodeName.toLowerCase() === 'i'){
20506 target = Roo.get(target).dom.parentNode;
20509 var nodeName = target.nodeName;
20510 var className = target.className;
20511 var html = target.innerHTML;
20513 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20517 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20519 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20525 picker : function()
20527 return this.pickerEl;
20530 fillMonths: function()
20533 var months = this.picker().select('>.datepicker-months td', true).first();
20535 months.dom.innerHTML = '';
20541 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20544 months.createChild(month);
20553 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20554 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20557 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20558 e.removeClass('active');
20560 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20561 e.addClass('active');
20568 if(this.isInline) {
20572 this.picker().removeClass(['bottom', 'top']);
20574 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20576 * place to the top of element!
20580 this.picker().addClass('top');
20581 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20586 this.picker().addClass('bottom');
20588 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20591 onFocus : function()
20593 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20597 onBlur : function()
20599 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20601 var d = this.inputEl().getValue();
20610 this.picker().show();
20611 this.picker().select('>.datepicker-months', true).first().show();
20615 this.fireEvent('show', this, this.date);
20620 if(this.isInline) {
20623 this.picker().hide();
20624 this.fireEvent('hide', this, this.date);
20628 onMousedown: function(e)
20630 e.stopPropagation();
20631 e.preventDefault();
20636 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20640 fireKey: function(e)
20642 if (!this.picker().isVisible()){
20643 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20654 e.preventDefault();
20658 dir = e.keyCode == 37 ? -1 : 1;
20660 this.vIndex = this.vIndex + dir;
20662 if(this.vIndex < 0){
20666 if(this.vIndex > 11){
20670 if(isNaN(this.vIndex)){
20674 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20680 dir = e.keyCode == 38 ? -1 : 1;
20682 this.vIndex = this.vIndex + dir * 4;
20684 if(this.vIndex < 0){
20688 if(this.vIndex > 11){
20692 if(isNaN(this.vIndex)){
20696 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20701 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20702 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20706 e.preventDefault();
20709 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20710 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20726 this.picker().remove();
20731 Roo.apply(Roo.bootstrap.MonthField, {
20750 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20751 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20756 Roo.apply(Roo.bootstrap.MonthField, {
20760 cls: 'datepicker dropdown-menu roo-dynamic',
20764 cls: 'datepicker-months',
20768 cls: 'table-condensed',
20770 Roo.bootstrap.DateField.content
20790 * @class Roo.bootstrap.CheckBox
20791 * @extends Roo.bootstrap.Input
20792 * Bootstrap CheckBox class
20794 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20795 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20796 * @cfg {String} boxLabel The text that appears beside the checkbox
20797 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20798 * @cfg {Boolean} checked initnal the element
20799 * @cfg {Boolean} inline inline the element (default false)
20800 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20801 * @cfg {String} tooltip label tooltip
20804 * Create a new CheckBox
20805 * @param {Object} config The config object
20808 Roo.bootstrap.CheckBox = function(config){
20809 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20814 * Fires when the element is checked or unchecked.
20815 * @param {Roo.bootstrap.CheckBox} this This input
20816 * @param {Boolean} checked The new checked value
20821 * Fires when the element is click.
20822 * @param {Roo.bootstrap.CheckBox} this This input
20829 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20831 inputType: 'checkbox',
20840 getAutoCreate : function()
20842 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20848 cfg.cls = 'form-group ' + this.inputType; //input-group
20851 cfg.cls += ' ' + this.inputType + '-inline';
20857 type : this.inputType,
20858 value : this.inputValue,
20859 cls : 'roo-' + this.inputType, //'form-box',
20860 placeholder : this.placeholder || ''
20864 if(this.inputType != 'radio'){
20868 cls : 'roo-hidden-value',
20869 value : this.checked ? this.inputValue : this.valueOff
20874 if (this.weight) { // Validity check?
20875 cfg.cls += " " + this.inputType + "-" + this.weight;
20878 if (this.disabled) {
20879 input.disabled=true;
20883 input.checked = this.checked;
20888 input.name = this.name;
20890 if(this.inputType != 'radio'){
20891 hidden.name = this.name;
20892 input.name = '_hidden_' + this.name;
20897 input.cls += ' input-' + this.size;
20902 ['xs','sm','md','lg'].map(function(size){
20903 if (settings[size]) {
20904 cfg.cls += ' col-' + size + '-' + settings[size];
20908 var inputblock = input;
20910 if (this.before || this.after) {
20913 cls : 'input-group',
20918 inputblock.cn.push({
20920 cls : 'input-group-addon',
20925 inputblock.cn.push(input);
20927 if(this.inputType != 'radio'){
20928 inputblock.cn.push(hidden);
20932 inputblock.cn.push({
20934 cls : 'input-group-addon',
20941 if (align ==='left' && this.fieldLabel.length) {
20942 // Roo.log("left and has label");
20947 cls : 'control-label',
20948 html : this.fieldLabel
20958 if(this.labelWidth > 12){
20959 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20962 if(this.labelWidth < 13 && this.labelmd == 0){
20963 this.labelmd = this.labelWidth;
20966 if(this.labellg > 0){
20967 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20968 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20971 if(this.labelmd > 0){
20972 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20973 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20976 if(this.labelsm > 0){
20977 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20978 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20981 if(this.labelxs > 0){
20982 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20983 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20986 } else if ( this.fieldLabel.length) {
20987 // Roo.log(" label");
20991 tag: this.boxLabel ? 'span' : 'label',
20993 cls: 'control-label box-input-label',
20994 //cls : 'input-group-addon',
20995 html : this.fieldLabel
21004 // Roo.log(" no label && no align");
21005 cfg.cn = [ inputblock ] ;
21011 var boxLabelCfg = {
21013 //'for': id, // box label is handled by onclick - so no for...
21015 html: this.boxLabel
21019 boxLabelCfg.tooltip = this.tooltip;
21022 cfg.cn.push(boxLabelCfg);
21025 if(this.inputType != 'radio'){
21026 cfg.cn.push(hidden);
21034 * return the real input element.
21036 inputEl: function ()
21038 return this.el.select('input.roo-' + this.inputType,true).first();
21040 hiddenEl: function ()
21042 return this.el.select('input.roo-hidden-value',true).first();
21045 labelEl: function()
21047 return this.el.select('label.control-label',true).first();
21049 /* depricated... */
21053 return this.labelEl();
21056 boxLabelEl: function()
21058 return this.el.select('label.box-label',true).first();
21061 initEvents : function()
21063 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21065 this.inputEl().on('click', this.onClick, this);
21067 if (this.boxLabel) {
21068 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21071 this.startValue = this.getValue();
21074 Roo.bootstrap.CheckBox.register(this);
21078 onClick : function(e)
21080 if(this.fireEvent('click', this, e) !== false){
21081 this.setChecked(!this.checked);
21086 setChecked : function(state,suppressEvent)
21088 this.startValue = this.getValue();
21090 if(this.inputType == 'radio'){
21092 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21093 e.dom.checked = false;
21096 this.inputEl().dom.checked = true;
21098 this.inputEl().dom.value = this.inputValue;
21100 if(suppressEvent !== true){
21101 this.fireEvent('check', this, true);
21109 this.checked = state;
21111 this.inputEl().dom.checked = state;
21114 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21116 if(suppressEvent !== true){
21117 this.fireEvent('check', this, state);
21123 getValue : function()
21125 if(this.inputType == 'radio'){
21126 return this.getGroupValue();
21129 return this.hiddenEl().dom.value;
21133 getGroupValue : function()
21135 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21139 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21142 setValue : function(v,suppressEvent)
21144 if(this.inputType == 'radio'){
21145 this.setGroupValue(v, suppressEvent);
21149 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21154 setGroupValue : function(v, suppressEvent)
21156 this.startValue = this.getValue();
21158 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21159 e.dom.checked = false;
21161 if(e.dom.value == v){
21162 e.dom.checked = true;
21166 if(suppressEvent !== true){
21167 this.fireEvent('check', this, true);
21175 validate : function()
21177 if(this.getVisibilityEl().hasClass('hidden')){
21183 (this.inputType == 'radio' && this.validateRadio()) ||
21184 (this.inputType == 'checkbox' && this.validateCheckbox())
21190 this.markInvalid();
21194 validateRadio : function()
21196 if(this.getVisibilityEl().hasClass('hidden')){
21200 if(this.allowBlank){
21206 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21207 if(!e.dom.checked){
21219 validateCheckbox : function()
21222 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21223 //return (this.getValue() == this.inputValue) ? true : false;
21226 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21234 for(var i in group){
21235 if(group[i].el.isVisible(true)){
21243 for(var i in group){
21248 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21255 * Mark this field as valid
21257 markValid : function()
21261 this.fireEvent('valid', this);
21263 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21266 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21273 if(this.inputType == 'radio'){
21274 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21275 var fg = e.findParent('.form-group', false, true);
21276 if (Roo.bootstrap.version == 3) {
21277 fg.removeClass([_this.invalidClass, _this.validClass]);
21278 fg.addClass(_this.validClass);
21280 fg.removeClass(['is-valid', 'is-invalid']);
21281 fg.addClass('is-valid');
21289 var fg = this.el.findParent('.form-group', false, true);
21290 if (Roo.bootstrap.version == 3) {
21291 fg.removeClass([this.invalidClass, this.validClass]);
21292 fg.addClass(this.validClass);
21294 fg.removeClass(['is-valid', 'is-invalid']);
21295 fg.addClass('is-valid');
21300 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21306 for(var i in group){
21307 var fg = group[i].el.findParent('.form-group', false, true);
21308 if (Roo.bootstrap.version == 3) {
21309 fg.removeClass([this.invalidClass, this.validClass]);
21310 fg.addClass(this.validClass);
21312 fg.removeClass(['is-valid', 'is-invalid']);
21313 fg.addClass('is-valid');
21319 * Mark this field as invalid
21320 * @param {String} msg The validation message
21322 markInvalid : function(msg)
21324 if(this.allowBlank){
21330 this.fireEvent('invalid', this, msg);
21332 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21335 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21339 label.markInvalid();
21342 if(this.inputType == 'radio'){
21344 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21345 var fg = e.findParent('.form-group', false, true);
21346 if (Roo.bootstrap.version == 3) {
21347 fg.removeClass([_this.invalidClass, _this.validClass]);
21348 fg.addClass(_this.invalidClass);
21350 fg.removeClass(['is-invalid', 'is-valid']);
21351 fg.addClass('is-invalid');
21359 var fg = this.el.findParent('.form-group', false, true);
21360 if (Roo.bootstrap.version == 3) {
21361 fg.removeClass([_this.invalidClass, _this.validClass]);
21362 fg.addClass(_this.invalidClass);
21364 fg.removeClass(['is-invalid', 'is-valid']);
21365 fg.addClass('is-invalid');
21370 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21376 for(var i in group){
21377 var fg = group[i].el.findParent('.form-group', false, true);
21378 if (Roo.bootstrap.version == 3) {
21379 fg.removeClass([_this.invalidClass, _this.validClass]);
21380 fg.addClass(_this.invalidClass);
21382 fg.removeClass(['is-invalid', 'is-valid']);
21383 fg.addClass('is-invalid');
21389 clearInvalid : function()
21391 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21393 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21395 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21397 if (label && label.iconEl) {
21398 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21399 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21403 disable : function()
21405 if(this.inputType != 'radio'){
21406 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21413 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21414 _this.getActionEl().addClass(this.disabledClass);
21415 e.dom.disabled = true;
21419 this.disabled = true;
21420 this.fireEvent("disable", this);
21424 enable : function()
21426 if(this.inputType != 'radio'){
21427 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21434 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21435 _this.getActionEl().removeClass(this.disabledClass);
21436 e.dom.disabled = false;
21440 this.disabled = false;
21441 this.fireEvent("enable", this);
21445 setBoxLabel : function(v)
21450 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21456 Roo.apply(Roo.bootstrap.CheckBox, {
21461 * register a CheckBox Group
21462 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21464 register : function(checkbox)
21466 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21467 this.groups[checkbox.groupId] = {};
21470 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21474 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21478 * fetch a CheckBox Group based on the group ID
21479 * @param {string} the group ID
21480 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21482 get: function(groupId) {
21483 if (typeof(this.groups[groupId]) == 'undefined') {
21487 return this.groups[groupId] ;
21500 * @class Roo.bootstrap.Radio
21501 * @extends Roo.bootstrap.Component
21502 * Bootstrap Radio class
21503 * @cfg {String} boxLabel - the label associated
21504 * @cfg {String} value - the value of radio
21507 * Create a new Radio
21508 * @param {Object} config The config object
21510 Roo.bootstrap.Radio = function(config){
21511 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21515 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21521 getAutoCreate : function()
21525 cls : 'form-group radio',
21530 html : this.boxLabel
21538 initEvents : function()
21540 this.parent().register(this);
21542 this.el.on('click', this.onClick, this);
21546 onClick : function(e)
21548 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21549 this.setChecked(true);
21553 setChecked : function(state, suppressEvent)
21555 this.parent().setValue(this.value, suppressEvent);
21559 setBoxLabel : function(v)
21564 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21579 * @class Roo.bootstrap.SecurePass
21580 * @extends Roo.bootstrap.Input
21581 * Bootstrap SecurePass class
21585 * Create a new SecurePass
21586 * @param {Object} config The config object
21589 Roo.bootstrap.SecurePass = function (config) {
21590 // these go here, so the translation tool can replace them..
21592 PwdEmpty: "Please type a password, and then retype it to confirm.",
21593 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21594 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21595 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21596 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21597 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21598 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21599 TooWeak: "Your password is Too Weak."
21601 this.meterLabel = "Password strength:";
21602 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21603 this.meterClass = [
21604 "roo-password-meter-tooweak",
21605 "roo-password-meter-weak",
21606 "roo-password-meter-medium",
21607 "roo-password-meter-strong",
21608 "roo-password-meter-grey"
21613 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21616 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21618 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21620 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21621 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21622 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21623 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21624 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21625 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21626 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21636 * @cfg {String/Object} Label for the strength meter (defaults to
21637 * 'Password strength:')
21642 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21643 * ['Weak', 'Medium', 'Strong'])
21646 pwdStrengths: false,
21659 initEvents: function ()
21661 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21663 if (this.el.is('input[type=password]') && Roo.isSafari) {
21664 this.el.on('keydown', this.SafariOnKeyDown, this);
21667 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21670 onRender: function (ct, position)
21672 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21673 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21674 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21676 this.trigger.createChild({
21681 cls: 'roo-password-meter-grey col-xs-12',
21684 //width: this.meterWidth + 'px'
21688 cls: 'roo-password-meter-text'
21694 if (this.hideTrigger) {
21695 this.trigger.setDisplayed(false);
21697 this.setSize(this.width || '', this.height || '');
21700 onDestroy: function ()
21702 if (this.trigger) {
21703 this.trigger.removeAllListeners();
21704 this.trigger.remove();
21707 this.wrap.remove();
21709 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21712 checkStrength: function ()
21714 var pwd = this.inputEl().getValue();
21715 if (pwd == this._lastPwd) {
21720 if (this.ClientSideStrongPassword(pwd)) {
21722 } else if (this.ClientSideMediumPassword(pwd)) {
21724 } else if (this.ClientSideWeakPassword(pwd)) {
21730 Roo.log('strength1: ' + strength);
21732 //var pm = this.trigger.child('div/div/div').dom;
21733 var pm = this.trigger.child('div/div');
21734 pm.removeClass(this.meterClass);
21735 pm.addClass(this.meterClass[strength]);
21738 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21740 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21742 this._lastPwd = pwd;
21746 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21748 this._lastPwd = '';
21750 var pm = this.trigger.child('div/div');
21751 pm.removeClass(this.meterClass);
21752 pm.addClass('roo-password-meter-grey');
21755 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21758 this.inputEl().dom.type='password';
21761 validateValue: function (value)
21764 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21767 if (value.length == 0) {
21768 if (this.allowBlank) {
21769 this.clearInvalid();
21773 this.markInvalid(this.errors.PwdEmpty);
21774 this.errorMsg = this.errors.PwdEmpty;
21782 if ('[\x21-\x7e]*'.match(value)) {
21783 this.markInvalid(this.errors.PwdBadChar);
21784 this.errorMsg = this.errors.PwdBadChar;
21787 if (value.length < 6) {
21788 this.markInvalid(this.errors.PwdShort);
21789 this.errorMsg = this.errors.PwdShort;
21792 if (value.length > 16) {
21793 this.markInvalid(this.errors.PwdLong);
21794 this.errorMsg = this.errors.PwdLong;
21798 if (this.ClientSideStrongPassword(value)) {
21800 } else if (this.ClientSideMediumPassword(value)) {
21802 } else if (this.ClientSideWeakPassword(value)) {
21809 if (strength < 2) {
21810 //this.markInvalid(this.errors.TooWeak);
21811 this.errorMsg = this.errors.TooWeak;
21816 console.log('strength2: ' + strength);
21818 //var pm = this.trigger.child('div/div/div').dom;
21820 var pm = this.trigger.child('div/div');
21821 pm.removeClass(this.meterClass);
21822 pm.addClass(this.meterClass[strength]);
21824 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21826 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21828 this.errorMsg = '';
21832 CharacterSetChecks: function (type)
21835 this.fResult = false;
21838 isctype: function (character, type)
21841 case this.kCapitalLetter:
21842 if (character >= 'A' && character <= 'Z') {
21847 case this.kSmallLetter:
21848 if (character >= 'a' && character <= 'z') {
21854 if (character >= '0' && character <= '9') {
21859 case this.kPunctuation:
21860 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21871 IsLongEnough: function (pwd, size)
21873 return !(pwd == null || isNaN(size) || pwd.length < size);
21876 SpansEnoughCharacterSets: function (word, nb)
21878 if (!this.IsLongEnough(word, nb))
21883 var characterSetChecks = new Array(
21884 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21885 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21888 for (var index = 0; index < word.length; ++index) {
21889 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21890 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21891 characterSetChecks[nCharSet].fResult = true;
21898 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21899 if (characterSetChecks[nCharSet].fResult) {
21904 if (nCharSets < nb) {
21910 ClientSideStrongPassword: function (pwd)
21912 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21915 ClientSideMediumPassword: function (pwd)
21917 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21920 ClientSideWeakPassword: function (pwd)
21922 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21925 })//<script type="text/javascript">
21928 * Based Ext JS Library 1.1.1
21929 * Copyright(c) 2006-2007, Ext JS, LLC.
21935 * @class Roo.HtmlEditorCore
21936 * @extends Roo.Component
21937 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21939 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21942 Roo.HtmlEditorCore = function(config){
21945 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21950 * @event initialize
21951 * Fires when the editor is fully initialized (including the iframe)
21952 * @param {Roo.HtmlEditorCore} this
21957 * Fires when the editor is first receives the focus. Any insertion must wait
21958 * until after this event.
21959 * @param {Roo.HtmlEditorCore} this
21963 * @event beforesync
21964 * Fires before the textarea is updated with content from the editor iframe. Return false
21965 * to cancel the sync.
21966 * @param {Roo.HtmlEditorCore} this
21967 * @param {String} html
21971 * @event beforepush
21972 * Fires before the iframe editor is updated with content from the textarea. Return false
21973 * to cancel the push.
21974 * @param {Roo.HtmlEditorCore} this
21975 * @param {String} html
21980 * Fires when the textarea is updated with content from the editor iframe.
21981 * @param {Roo.HtmlEditorCore} this
21982 * @param {String} html
21987 * Fires when the iframe editor is updated with content from the textarea.
21988 * @param {Roo.HtmlEditorCore} this
21989 * @param {String} html
21994 * @event editorevent
21995 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21996 * @param {Roo.HtmlEditorCore} this
22002 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22004 // defaults : white / black...
22005 this.applyBlacklists();
22012 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22016 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22022 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22027 * @cfg {Number} height (in pixels)
22031 * @cfg {Number} width (in pixels)
22036 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22039 stylesheets: false,
22044 // private properties
22045 validationEvent : false,
22047 initialized : false,
22049 sourceEditMode : false,
22050 onFocus : Roo.emptyFn,
22052 hideMode:'offsets',
22056 // blacklist + whitelisted elements..
22063 * Protected method that will not generally be called directly. It
22064 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22065 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22067 getDocMarkup : function(){
22071 // inherit styels from page...??
22072 if (this.stylesheets === false) {
22074 Roo.get(document.head).select('style').each(function(node) {
22075 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22078 Roo.get(document.head).select('link').each(function(node) {
22079 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22082 } else if (!this.stylesheets.length) {
22084 st = '<style type="text/css">' +
22085 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22088 st = '<style type="text/css">' +
22093 st += '<style type="text/css">' +
22094 'IMG { cursor: pointer } ' +
22097 var cls = 'roo-htmleditor-body';
22099 if(this.bodyCls.length){
22100 cls += ' ' + this.bodyCls;
22103 return '<html><head>' + st +
22104 //<style type="text/css">' +
22105 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22107 ' </head><body class="' + cls + '"></body></html>';
22111 onRender : function(ct, position)
22114 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22115 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22118 this.el.dom.style.border = '0 none';
22119 this.el.dom.setAttribute('tabIndex', -1);
22120 this.el.addClass('x-hidden hide');
22124 if(Roo.isIE){ // fix IE 1px bogus margin
22125 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22129 this.frameId = Roo.id();
22133 var iframe = this.owner.wrap.createChild({
22135 cls: 'form-control', // bootstrap..
22137 name: this.frameId,
22138 frameBorder : 'no',
22139 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22144 this.iframe = iframe.dom;
22146 this.assignDocWin();
22148 this.doc.designMode = 'on';
22151 this.doc.write(this.getDocMarkup());
22155 var task = { // must defer to wait for browser to be ready
22157 //console.log("run task?" + this.doc.readyState);
22158 this.assignDocWin();
22159 if(this.doc.body || this.doc.readyState == 'complete'){
22161 this.doc.designMode="on";
22165 Roo.TaskMgr.stop(task);
22166 this.initEditor.defer(10, this);
22173 Roo.TaskMgr.start(task);
22178 onResize : function(w, h)
22180 Roo.log('resize: ' +w + ',' + h );
22181 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22185 if(typeof w == 'number'){
22187 this.iframe.style.width = w + 'px';
22189 if(typeof h == 'number'){
22191 this.iframe.style.height = h + 'px';
22193 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22200 * Toggles the editor between standard and source edit mode.
22201 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22203 toggleSourceEdit : function(sourceEditMode){
22205 this.sourceEditMode = sourceEditMode === true;
22207 if(this.sourceEditMode){
22209 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22212 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22213 //this.iframe.className = '';
22216 //this.setSize(this.owner.wrap.getSize());
22217 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22224 * Protected method that will not generally be called directly. If you need/want
22225 * custom HTML cleanup, this is the method you should override.
22226 * @param {String} html The HTML to be cleaned
22227 * return {String} The cleaned HTML
22229 cleanHtml : function(html){
22230 html = String(html);
22231 if(html.length > 5){
22232 if(Roo.isSafari){ // strip safari nonsense
22233 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22236 if(html == ' '){
22243 * HTML Editor -> Textarea
22244 * Protected method that will not generally be called directly. Syncs the contents
22245 * of the editor iframe with the textarea.
22247 syncValue : function(){
22248 if(this.initialized){
22249 var bd = (this.doc.body || this.doc.documentElement);
22250 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22251 var html = bd.innerHTML;
22253 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22254 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22256 html = '<div style="'+m[0]+'">' + html + '</div>';
22259 html = this.cleanHtml(html);
22260 // fix up the special chars.. normaly like back quotes in word...
22261 // however we do not want to do this with chinese..
22262 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22263 var cc = b.charCodeAt();
22265 (cc >= 0x4E00 && cc < 0xA000 ) ||
22266 (cc >= 0x3400 && cc < 0x4E00 ) ||
22267 (cc >= 0xf900 && cc < 0xfb00 )
22273 if(this.owner.fireEvent('beforesync', this, html) !== false){
22274 this.el.dom.value = html;
22275 this.owner.fireEvent('sync', this, html);
22281 * Protected method that will not generally be called directly. Pushes the value of the textarea
22282 * into the iframe editor.
22284 pushValue : function(){
22285 if(this.initialized){
22286 var v = this.el.dom.value.trim();
22288 // if(v.length < 1){
22292 if(this.owner.fireEvent('beforepush', this, v) !== false){
22293 var d = (this.doc.body || this.doc.documentElement);
22295 this.cleanUpPaste();
22296 this.el.dom.value = d.innerHTML;
22297 this.owner.fireEvent('push', this, v);
22303 deferFocus : function(){
22304 this.focus.defer(10, this);
22308 focus : function(){
22309 if(this.win && !this.sourceEditMode){
22316 assignDocWin: function()
22318 var iframe = this.iframe;
22321 this.doc = iframe.contentWindow.document;
22322 this.win = iframe.contentWindow;
22324 // if (!Roo.get(this.frameId)) {
22327 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22328 // this.win = Roo.get(this.frameId).dom.contentWindow;
22330 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22334 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22335 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22340 initEditor : function(){
22341 //console.log("INIT EDITOR");
22342 this.assignDocWin();
22346 this.doc.designMode="on";
22348 this.doc.write(this.getDocMarkup());
22351 var dbody = (this.doc.body || this.doc.documentElement);
22352 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22353 // this copies styles from the containing element into thsi one..
22354 // not sure why we need all of this..
22355 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22357 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22358 //ss['background-attachment'] = 'fixed'; // w3c
22359 dbody.bgProperties = 'fixed'; // ie
22360 //Roo.DomHelper.applyStyles(dbody, ss);
22361 Roo.EventManager.on(this.doc, {
22362 //'mousedown': this.onEditorEvent,
22363 'mouseup': this.onEditorEvent,
22364 'dblclick': this.onEditorEvent,
22365 'click': this.onEditorEvent,
22366 'keyup': this.onEditorEvent,
22371 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22373 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22374 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22376 this.initialized = true;
22378 this.owner.fireEvent('initialize', this);
22383 onDestroy : function(){
22389 //for (var i =0; i < this.toolbars.length;i++) {
22390 // // fixme - ask toolbars for heights?
22391 // this.toolbars[i].onDestroy();
22394 //this.wrap.dom.innerHTML = '';
22395 //this.wrap.remove();
22400 onFirstFocus : function(){
22402 this.assignDocWin();
22405 this.activated = true;
22408 if(Roo.isGecko){ // prevent silly gecko errors
22410 var s = this.win.getSelection();
22411 if(!s.focusNode || s.focusNode.nodeType != 3){
22412 var r = s.getRangeAt(0);
22413 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22418 this.execCmd('useCSS', true);
22419 this.execCmd('styleWithCSS', false);
22422 this.owner.fireEvent('activate', this);
22426 adjustFont: function(btn){
22427 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22428 //if(Roo.isSafari){ // safari
22431 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22432 if(Roo.isSafari){ // safari
22433 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22434 v = (v < 10) ? 10 : v;
22435 v = (v > 48) ? 48 : v;
22436 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22441 v = Math.max(1, v+adjust);
22443 this.execCmd('FontSize', v );
22446 onEditorEvent : function(e)
22448 this.owner.fireEvent('editorevent', this, e);
22449 // this.updateToolbar();
22450 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22453 insertTag : function(tg)
22455 // could be a bit smarter... -> wrap the current selected tRoo..
22456 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22458 range = this.createRange(this.getSelection());
22459 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22460 wrappingNode.appendChild(range.extractContents());
22461 range.insertNode(wrappingNode);
22468 this.execCmd("formatblock", tg);
22472 insertText : function(txt)
22476 var range = this.createRange();
22477 range.deleteContents();
22478 //alert(Sender.getAttribute('label'));
22480 range.insertNode(this.doc.createTextNode(txt));
22486 * Executes a Midas editor command on the editor document and performs necessary focus and
22487 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22488 * @param {String} cmd The Midas command
22489 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22491 relayCmd : function(cmd, value){
22493 this.execCmd(cmd, value);
22494 this.owner.fireEvent('editorevent', this);
22495 //this.updateToolbar();
22496 this.owner.deferFocus();
22500 * Executes a Midas editor command directly on the editor document.
22501 * For visual commands, you should use {@link #relayCmd} instead.
22502 * <b>This should only be called after the editor is initialized.</b>
22503 * @param {String} cmd The Midas command
22504 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22506 execCmd : function(cmd, value){
22507 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22514 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22516 * @param {String} text | dom node..
22518 insertAtCursor : function(text)
22521 if(!this.activated){
22527 var r = this.doc.selection.createRange();
22538 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22542 // from jquery ui (MIT licenced)
22544 var win = this.win;
22546 if (win.getSelection && win.getSelection().getRangeAt) {
22547 range = win.getSelection().getRangeAt(0);
22548 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22549 range.insertNode(node);
22550 } else if (win.document.selection && win.document.selection.createRange) {
22551 // no firefox support
22552 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22553 win.document.selection.createRange().pasteHTML(txt);
22555 // no firefox support
22556 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22557 this.execCmd('InsertHTML', txt);
22566 mozKeyPress : function(e){
22568 var c = e.getCharCode(), cmd;
22571 c = String.fromCharCode(c).toLowerCase();
22585 this.cleanUpPaste.defer(100, this);
22593 e.preventDefault();
22601 fixKeys : function(){ // load time branching for fastest keydown performance
22603 return function(e){
22604 var k = e.getKey(), r;
22607 r = this.doc.selection.createRange();
22610 r.pasteHTML('    ');
22617 r = this.doc.selection.createRange();
22619 var target = r.parentElement();
22620 if(!target || target.tagName.toLowerCase() != 'li'){
22622 r.pasteHTML('<br />');
22628 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22629 this.cleanUpPaste.defer(100, this);
22635 }else if(Roo.isOpera){
22636 return function(e){
22637 var k = e.getKey();
22641 this.execCmd('InsertHTML','    ');
22644 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22645 this.cleanUpPaste.defer(100, this);
22650 }else if(Roo.isSafari){
22651 return function(e){
22652 var k = e.getKey();
22656 this.execCmd('InsertText','\t');
22660 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22661 this.cleanUpPaste.defer(100, this);
22669 getAllAncestors: function()
22671 var p = this.getSelectedNode();
22674 a.push(p); // push blank onto stack..
22675 p = this.getParentElement();
22679 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22683 a.push(this.doc.body);
22687 lastSelNode : false,
22690 getSelection : function()
22692 this.assignDocWin();
22693 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22696 getSelectedNode: function()
22698 // this may only work on Gecko!!!
22700 // should we cache this!!!!
22705 var range = this.createRange(this.getSelection()).cloneRange();
22708 var parent = range.parentElement();
22710 var testRange = range.duplicate();
22711 testRange.moveToElementText(parent);
22712 if (testRange.inRange(range)) {
22715 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22718 parent = parent.parentElement;
22723 // is ancestor a text element.
22724 var ac = range.commonAncestorContainer;
22725 if (ac.nodeType == 3) {
22726 ac = ac.parentNode;
22729 var ar = ac.childNodes;
22732 var other_nodes = [];
22733 var has_other_nodes = false;
22734 for (var i=0;i<ar.length;i++) {
22735 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22738 // fullly contained node.
22740 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22745 // probably selected..
22746 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22747 other_nodes.push(ar[i]);
22751 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22756 has_other_nodes = true;
22758 if (!nodes.length && other_nodes.length) {
22759 nodes= other_nodes;
22761 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22767 createRange: function(sel)
22769 // this has strange effects when using with
22770 // top toolbar - not sure if it's a great idea.
22771 //this.editor.contentWindow.focus();
22772 if (typeof sel != "undefined") {
22774 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22776 return this.doc.createRange();
22779 return this.doc.createRange();
22782 getParentElement: function()
22785 this.assignDocWin();
22786 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22788 var range = this.createRange(sel);
22791 var p = range.commonAncestorContainer;
22792 while (p.nodeType == 3) { // text node
22803 * Range intersection.. the hard stuff...
22807 * [ -- selected range --- ]
22811 * if end is before start or hits it. fail.
22812 * if start is after end or hits it fail.
22814 * if either hits (but other is outside. - then it's not
22820 // @see http://www.thismuchiknow.co.uk/?p=64.
22821 rangeIntersectsNode : function(range, node)
22823 var nodeRange = node.ownerDocument.createRange();
22825 nodeRange.selectNode(node);
22827 nodeRange.selectNodeContents(node);
22830 var rangeStartRange = range.cloneRange();
22831 rangeStartRange.collapse(true);
22833 var rangeEndRange = range.cloneRange();
22834 rangeEndRange.collapse(false);
22836 var nodeStartRange = nodeRange.cloneRange();
22837 nodeStartRange.collapse(true);
22839 var nodeEndRange = nodeRange.cloneRange();
22840 nodeEndRange.collapse(false);
22842 return rangeStartRange.compareBoundaryPoints(
22843 Range.START_TO_START, nodeEndRange) == -1 &&
22844 rangeEndRange.compareBoundaryPoints(
22845 Range.START_TO_START, nodeStartRange) == 1;
22849 rangeCompareNode : function(range, node)
22851 var nodeRange = node.ownerDocument.createRange();
22853 nodeRange.selectNode(node);
22855 nodeRange.selectNodeContents(node);
22859 range.collapse(true);
22861 nodeRange.collapse(true);
22863 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22864 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22866 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22868 var nodeIsBefore = ss == 1;
22869 var nodeIsAfter = ee == -1;
22871 if (nodeIsBefore && nodeIsAfter) {
22874 if (!nodeIsBefore && nodeIsAfter) {
22875 return 1; //right trailed.
22878 if (nodeIsBefore && !nodeIsAfter) {
22879 return 2; // left trailed.
22885 // private? - in a new class?
22886 cleanUpPaste : function()
22888 // cleans up the whole document..
22889 Roo.log('cleanuppaste');
22891 this.cleanUpChildren(this.doc.body);
22892 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22893 if (clean != this.doc.body.innerHTML) {
22894 this.doc.body.innerHTML = clean;
22899 cleanWordChars : function(input) {// change the chars to hex code
22900 var he = Roo.HtmlEditorCore;
22902 var output = input;
22903 Roo.each(he.swapCodes, function(sw) {
22904 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22906 output = output.replace(swapper, sw[1]);
22913 cleanUpChildren : function (n)
22915 if (!n.childNodes.length) {
22918 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22919 this.cleanUpChild(n.childNodes[i]);
22926 cleanUpChild : function (node)
22929 //console.log(node);
22930 if (node.nodeName == "#text") {
22931 // clean up silly Windows -- stuff?
22934 if (node.nodeName == "#comment") {
22935 node.parentNode.removeChild(node);
22936 // clean up silly Windows -- stuff?
22939 var lcname = node.tagName.toLowerCase();
22940 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22941 // whitelist of tags..
22943 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22945 node.parentNode.removeChild(node);
22950 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22952 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22953 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22955 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22956 // remove_keep_children = true;
22959 if (remove_keep_children) {
22960 this.cleanUpChildren(node);
22961 // inserts everything just before this node...
22962 while (node.childNodes.length) {
22963 var cn = node.childNodes[0];
22964 node.removeChild(cn);
22965 node.parentNode.insertBefore(cn, node);
22967 node.parentNode.removeChild(node);
22971 if (!node.attributes || !node.attributes.length) {
22972 this.cleanUpChildren(node);
22976 function cleanAttr(n,v)
22979 if (v.match(/^\./) || v.match(/^\//)) {
22982 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22985 if (v.match(/^#/)) {
22988 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22989 node.removeAttribute(n);
22993 var cwhite = this.cwhite;
22994 var cblack = this.cblack;
22996 function cleanStyle(n,v)
22998 if (v.match(/expression/)) { //XSS?? should we even bother..
22999 node.removeAttribute(n);
23003 var parts = v.split(/;/);
23006 Roo.each(parts, function(p) {
23007 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23011 var l = p.split(':').shift().replace(/\s+/g,'');
23012 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23014 if ( cwhite.length && cblack.indexOf(l) > -1) {
23015 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23016 //node.removeAttribute(n);
23020 // only allow 'c whitelisted system attributes'
23021 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23022 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23023 //node.removeAttribute(n);
23033 if (clean.length) {
23034 node.setAttribute(n, clean.join(';'));
23036 node.removeAttribute(n);
23042 for (var i = node.attributes.length-1; i > -1 ; i--) {
23043 var a = node.attributes[i];
23046 if (a.name.toLowerCase().substr(0,2)=='on') {
23047 node.removeAttribute(a.name);
23050 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23051 node.removeAttribute(a.name);
23054 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23055 cleanAttr(a.name,a.value); // fixme..
23058 if (a.name == 'style') {
23059 cleanStyle(a.name,a.value);
23062 /// clean up MS crap..
23063 // tecnically this should be a list of valid class'es..
23066 if (a.name == 'class') {
23067 if (a.value.match(/^Mso/)) {
23068 node.className = '';
23071 if (a.value.match(/^body$/)) {
23072 node.className = '';
23083 this.cleanUpChildren(node);
23089 * Clean up MS wordisms...
23091 cleanWord : function(node)
23096 this.cleanWord(this.doc.body);
23099 if (node.nodeName == "#text") {
23100 // clean up silly Windows -- stuff?
23103 if (node.nodeName == "#comment") {
23104 node.parentNode.removeChild(node);
23105 // clean up silly Windows -- stuff?
23109 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23110 node.parentNode.removeChild(node);
23114 // remove - but keep children..
23115 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23116 while (node.childNodes.length) {
23117 var cn = node.childNodes[0];
23118 node.removeChild(cn);
23119 node.parentNode.insertBefore(cn, node);
23121 node.parentNode.removeChild(node);
23122 this.iterateChildren(node, this.cleanWord);
23126 if (node.className.length) {
23128 var cn = node.className.split(/\W+/);
23130 Roo.each(cn, function(cls) {
23131 if (cls.match(/Mso[a-zA-Z]+/)) {
23136 node.className = cna.length ? cna.join(' ') : '';
23138 node.removeAttribute("class");
23142 if (node.hasAttribute("lang")) {
23143 node.removeAttribute("lang");
23146 if (node.hasAttribute("style")) {
23148 var styles = node.getAttribute("style").split(";");
23150 Roo.each(styles, function(s) {
23151 if (!s.match(/:/)) {
23154 var kv = s.split(":");
23155 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23158 // what ever is left... we allow.
23161 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23162 if (!nstyle.length) {
23163 node.removeAttribute('style');
23166 this.iterateChildren(node, this.cleanWord);
23172 * iterateChildren of a Node, calling fn each time, using this as the scole..
23173 * @param {DomNode} node node to iterate children of.
23174 * @param {Function} fn method of this class to call on each item.
23176 iterateChildren : function(node, fn)
23178 if (!node.childNodes.length) {
23181 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23182 fn.call(this, node.childNodes[i])
23188 * cleanTableWidths.
23190 * Quite often pasting from word etc.. results in tables with column and widths.
23191 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23194 cleanTableWidths : function(node)
23199 this.cleanTableWidths(this.doc.body);
23204 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23207 Roo.log(node.tagName);
23208 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23209 this.iterateChildren(node, this.cleanTableWidths);
23212 if (node.hasAttribute('width')) {
23213 node.removeAttribute('width');
23217 if (node.hasAttribute("style")) {
23220 var styles = node.getAttribute("style").split(";");
23222 Roo.each(styles, function(s) {
23223 if (!s.match(/:/)) {
23226 var kv = s.split(":");
23227 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23230 // what ever is left... we allow.
23233 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23234 if (!nstyle.length) {
23235 node.removeAttribute('style');
23239 this.iterateChildren(node, this.cleanTableWidths);
23247 domToHTML : function(currentElement, depth, nopadtext) {
23249 depth = depth || 0;
23250 nopadtext = nopadtext || false;
23252 if (!currentElement) {
23253 return this.domToHTML(this.doc.body);
23256 //Roo.log(currentElement);
23258 var allText = false;
23259 var nodeName = currentElement.nodeName;
23260 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23262 if (nodeName == '#text') {
23264 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23269 if (nodeName != 'BODY') {
23272 // Prints the node tagName, such as <A>, <IMG>, etc
23275 for(i = 0; i < currentElement.attributes.length;i++) {
23277 var aname = currentElement.attributes.item(i).name;
23278 if (!currentElement.attributes.item(i).value.length) {
23281 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23284 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23293 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23296 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23301 // Traverse the tree
23303 var currentElementChild = currentElement.childNodes.item(i);
23304 var allText = true;
23305 var innerHTML = '';
23307 while (currentElementChild) {
23308 // Formatting code (indent the tree so it looks nice on the screen)
23309 var nopad = nopadtext;
23310 if (lastnode == 'SPAN') {
23314 if (currentElementChild.nodeName == '#text') {
23315 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23316 toadd = nopadtext ? toadd : toadd.trim();
23317 if (!nopad && toadd.length > 80) {
23318 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23320 innerHTML += toadd;
23323 currentElementChild = currentElement.childNodes.item(i);
23329 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23331 // Recursively traverse the tree structure of the child node
23332 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23333 lastnode = currentElementChild.nodeName;
23335 currentElementChild=currentElement.childNodes.item(i);
23341 // The remaining code is mostly for formatting the tree
23342 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23347 ret+= "</"+tagName+">";
23353 applyBlacklists : function()
23355 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23356 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23360 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23361 if (b.indexOf(tag) > -1) {
23364 this.white.push(tag);
23368 Roo.each(w, function(tag) {
23369 if (b.indexOf(tag) > -1) {
23372 if (this.white.indexOf(tag) > -1) {
23375 this.white.push(tag);
23380 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23381 if (w.indexOf(tag) > -1) {
23384 this.black.push(tag);
23388 Roo.each(b, function(tag) {
23389 if (w.indexOf(tag) > -1) {
23392 if (this.black.indexOf(tag) > -1) {
23395 this.black.push(tag);
23400 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23401 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23405 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23406 if (b.indexOf(tag) > -1) {
23409 this.cwhite.push(tag);
23413 Roo.each(w, function(tag) {
23414 if (b.indexOf(tag) > -1) {
23417 if (this.cwhite.indexOf(tag) > -1) {
23420 this.cwhite.push(tag);
23425 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23426 if (w.indexOf(tag) > -1) {
23429 this.cblack.push(tag);
23433 Roo.each(b, function(tag) {
23434 if (w.indexOf(tag) > -1) {
23437 if (this.cblack.indexOf(tag) > -1) {
23440 this.cblack.push(tag);
23445 setStylesheets : function(stylesheets)
23447 if(typeof(stylesheets) == 'string'){
23448 Roo.get(this.iframe.contentDocument.head).createChild({
23450 rel : 'stylesheet',
23459 Roo.each(stylesheets, function(s) {
23464 Roo.get(_this.iframe.contentDocument.head).createChild({
23466 rel : 'stylesheet',
23475 removeStylesheets : function()
23479 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23484 setStyle : function(style)
23486 Roo.get(this.iframe.contentDocument.head).createChild({
23495 // hide stuff that is not compatible
23509 * @event specialkey
23513 * @cfg {String} fieldClass @hide
23516 * @cfg {String} focusClass @hide
23519 * @cfg {String} autoCreate @hide
23522 * @cfg {String} inputType @hide
23525 * @cfg {String} invalidClass @hide
23528 * @cfg {String} invalidText @hide
23531 * @cfg {String} msgFx @hide
23534 * @cfg {String} validateOnBlur @hide
23538 Roo.HtmlEditorCore.white = [
23539 'area', 'br', 'img', 'input', 'hr', 'wbr',
23541 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23542 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23543 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23544 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23545 'table', 'ul', 'xmp',
23547 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23550 'dir', 'menu', 'ol', 'ul', 'dl',
23556 Roo.HtmlEditorCore.black = [
23557 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23559 'base', 'basefont', 'bgsound', 'blink', 'body',
23560 'frame', 'frameset', 'head', 'html', 'ilayer',
23561 'iframe', 'layer', 'link', 'meta', 'object',
23562 'script', 'style' ,'title', 'xml' // clean later..
23564 Roo.HtmlEditorCore.clean = [
23565 'script', 'style', 'title', 'xml'
23567 Roo.HtmlEditorCore.remove = [
23572 Roo.HtmlEditorCore.ablack = [
23576 Roo.HtmlEditorCore.aclean = [
23577 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23581 Roo.HtmlEditorCore.pwhite= [
23582 'http', 'https', 'mailto'
23585 // white listed style attributes.
23586 Roo.HtmlEditorCore.cwhite= [
23587 // 'text-align', /// default is to allow most things..
23593 // black listed style attributes.
23594 Roo.HtmlEditorCore.cblack= [
23595 // 'font-size' -- this can be set by the project
23599 Roo.HtmlEditorCore.swapCodes =[
23618 * @class Roo.bootstrap.HtmlEditor
23619 * @extends Roo.bootstrap.TextArea
23620 * Bootstrap HtmlEditor class
23623 * Create a new HtmlEditor
23624 * @param {Object} config The config object
23627 Roo.bootstrap.HtmlEditor = function(config){
23628 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23629 if (!this.toolbars) {
23630 this.toolbars = [];
23633 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23636 * @event initialize
23637 * Fires when the editor is fully initialized (including the iframe)
23638 * @param {HtmlEditor} this
23643 * Fires when the editor is first receives the focus. Any insertion must wait
23644 * until after this event.
23645 * @param {HtmlEditor} this
23649 * @event beforesync
23650 * Fires before the textarea is updated with content from the editor iframe. Return false
23651 * to cancel the sync.
23652 * @param {HtmlEditor} this
23653 * @param {String} html
23657 * @event beforepush
23658 * Fires before the iframe editor is updated with content from the textarea. Return false
23659 * to cancel the push.
23660 * @param {HtmlEditor} this
23661 * @param {String} html
23666 * Fires when the textarea is updated with content from the editor iframe.
23667 * @param {HtmlEditor} this
23668 * @param {String} html
23673 * Fires when the iframe editor is updated with content from the textarea.
23674 * @param {HtmlEditor} this
23675 * @param {String} html
23679 * @event editmodechange
23680 * Fires when the editor switches edit modes
23681 * @param {HtmlEditor} this
23682 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23684 editmodechange: true,
23686 * @event editorevent
23687 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23688 * @param {HtmlEditor} this
23692 * @event firstfocus
23693 * Fires when on first focus - needed by toolbars..
23694 * @param {HtmlEditor} this
23699 * Auto save the htmlEditor value as a file into Events
23700 * @param {HtmlEditor} this
23704 * @event savedpreview
23705 * preview the saved version of htmlEditor
23706 * @param {HtmlEditor} this
23713 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23717 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23722 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23727 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23732 * @cfg {Number} height (in pixels)
23736 * @cfg {Number} width (in pixels)
23741 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23744 stylesheets: false,
23749 // private properties
23750 validationEvent : false,
23752 initialized : false,
23755 onFocus : Roo.emptyFn,
23757 hideMode:'offsets',
23759 tbContainer : false,
23763 toolbarContainer :function() {
23764 return this.wrap.select('.x-html-editor-tb',true).first();
23768 * Protected method that will not generally be called directly. It
23769 * is called when the editor creates its toolbar. Override this method if you need to
23770 * add custom toolbar buttons.
23771 * @param {HtmlEditor} editor
23773 createToolbar : function(){
23774 Roo.log('renewing');
23775 Roo.log("create toolbars");
23777 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23778 this.toolbars[0].render(this.toolbarContainer());
23782 // if (!editor.toolbars || !editor.toolbars.length) {
23783 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23786 // for (var i =0 ; i < editor.toolbars.length;i++) {
23787 // editor.toolbars[i] = Roo.factory(
23788 // typeof(editor.toolbars[i]) == 'string' ?
23789 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23790 // Roo.bootstrap.HtmlEditor);
23791 // editor.toolbars[i].init(editor);
23797 onRender : function(ct, position)
23799 // Roo.log("Call onRender: " + this.xtype);
23801 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23803 this.wrap = this.inputEl().wrap({
23804 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23807 this.editorcore.onRender(ct, position);
23809 if (this.resizable) {
23810 this.resizeEl = new Roo.Resizable(this.wrap, {
23814 minHeight : this.height,
23815 height: this.height,
23816 handles : this.resizable,
23819 resize : function(r, w, h) {
23820 _t.onResize(w,h); // -something
23826 this.createToolbar(this);
23829 if(!this.width && this.resizable){
23830 this.setSize(this.wrap.getSize());
23832 if (this.resizeEl) {
23833 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23834 // should trigger onReize..
23840 onResize : function(w, h)
23842 Roo.log('resize: ' +w + ',' + h );
23843 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23847 if(this.inputEl() ){
23848 if(typeof w == 'number'){
23849 var aw = w - this.wrap.getFrameWidth('lr');
23850 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23853 if(typeof h == 'number'){
23854 var tbh = -11; // fixme it needs to tool bar size!
23855 for (var i =0; i < this.toolbars.length;i++) {
23856 // fixme - ask toolbars for heights?
23857 tbh += this.toolbars[i].el.getHeight();
23858 //if (this.toolbars[i].footer) {
23859 // tbh += this.toolbars[i].footer.el.getHeight();
23867 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23868 ah -= 5; // knock a few pixes off for look..
23869 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23873 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23874 this.editorcore.onResize(ew,eh);
23879 * Toggles the editor between standard and source edit mode.
23880 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23882 toggleSourceEdit : function(sourceEditMode)
23884 this.editorcore.toggleSourceEdit(sourceEditMode);
23886 if(this.editorcore.sourceEditMode){
23887 Roo.log('editor - showing textarea');
23890 // Roo.log(this.syncValue());
23892 this.inputEl().removeClass(['hide', 'x-hidden']);
23893 this.inputEl().dom.removeAttribute('tabIndex');
23894 this.inputEl().focus();
23896 Roo.log('editor - hiding textarea');
23898 // Roo.log(this.pushValue());
23901 this.inputEl().addClass(['hide', 'x-hidden']);
23902 this.inputEl().dom.setAttribute('tabIndex', -1);
23903 //this.deferFocus();
23906 if(this.resizable){
23907 this.setSize(this.wrap.getSize());
23910 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23913 // private (for BoxComponent)
23914 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23916 // private (for BoxComponent)
23917 getResizeEl : function(){
23921 // private (for BoxComponent)
23922 getPositionEl : function(){
23927 initEvents : function(){
23928 this.originalValue = this.getValue();
23932 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23935 // markInvalid : Roo.emptyFn,
23937 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23940 // clearInvalid : Roo.emptyFn,
23942 setValue : function(v){
23943 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23944 this.editorcore.pushValue();
23949 deferFocus : function(){
23950 this.focus.defer(10, this);
23954 focus : function(){
23955 this.editorcore.focus();
23961 onDestroy : function(){
23967 for (var i =0; i < this.toolbars.length;i++) {
23968 // fixme - ask toolbars for heights?
23969 this.toolbars[i].onDestroy();
23972 this.wrap.dom.innerHTML = '';
23973 this.wrap.remove();
23978 onFirstFocus : function(){
23979 //Roo.log("onFirstFocus");
23980 this.editorcore.onFirstFocus();
23981 for (var i =0; i < this.toolbars.length;i++) {
23982 this.toolbars[i].onFirstFocus();
23988 syncValue : function()
23990 this.editorcore.syncValue();
23993 pushValue : function()
23995 this.editorcore.pushValue();
23999 // hide stuff that is not compatible
24013 * @event specialkey
24017 * @cfg {String} fieldClass @hide
24020 * @cfg {String} focusClass @hide
24023 * @cfg {String} autoCreate @hide
24026 * @cfg {String} inputType @hide
24030 * @cfg {String} invalidText @hide
24033 * @cfg {String} msgFx @hide
24036 * @cfg {String} validateOnBlur @hide
24045 Roo.namespace('Roo.bootstrap.htmleditor');
24047 * @class Roo.bootstrap.HtmlEditorToolbar1
24052 new Roo.bootstrap.HtmlEditor({
24055 new Roo.bootstrap.HtmlEditorToolbar1({
24056 disable : { fonts: 1 , format: 1, ..., ... , ...],
24062 * @cfg {Object} disable List of elements to disable..
24063 * @cfg {Array} btns List of additional buttons.
24067 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24070 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24073 Roo.apply(this, config);
24075 // default disabled, based on 'good practice'..
24076 this.disable = this.disable || {};
24077 Roo.applyIf(this.disable, {
24080 specialElements : true
24082 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24084 this.editor = config.editor;
24085 this.editorcore = config.editor.editorcore;
24087 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24089 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24090 // dont call parent... till later.
24092 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24097 editorcore : false,
24102 "h1","h2","h3","h4","h5","h6",
24104 "abbr", "acronym", "address", "cite", "samp", "var",
24108 onRender : function(ct, position)
24110 // Roo.log("Call onRender: " + this.xtype);
24112 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24114 this.el.dom.style.marginBottom = '0';
24116 var editorcore = this.editorcore;
24117 var editor= this.editor;
24120 var btn = function(id,cmd , toggle, handler, html){
24122 var event = toggle ? 'toggle' : 'click';
24127 xns: Roo.bootstrap,
24131 enableToggle:toggle !== false,
24133 pressed : toggle ? false : null,
24136 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24137 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24143 // var cb_box = function...
24148 xns: Roo.bootstrap,
24153 xns: Roo.bootstrap,
24157 Roo.each(this.formats, function(f) {
24158 style.menu.items.push({
24160 xns: Roo.bootstrap,
24161 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24166 editorcore.insertTag(this.tagname);
24173 children.push(style);
24175 btn('bold',false,true);
24176 btn('italic',false,true);
24177 btn('align-left', 'justifyleft',true);
24178 btn('align-center', 'justifycenter',true);
24179 btn('align-right' , 'justifyright',true);
24180 btn('link', false, false, function(btn) {
24181 //Roo.log("create link?");
24182 var url = prompt(this.createLinkText, this.defaultLinkValue);
24183 if(url && url != 'http:/'+'/'){
24184 this.editorcore.relayCmd('createlink', url);
24187 btn('list','insertunorderedlist',true);
24188 btn('pencil', false,true, function(btn){
24190 this.toggleSourceEdit(btn.pressed);
24193 if (this.editor.btns.length > 0) {
24194 for (var i = 0; i<this.editor.btns.length; i++) {
24195 children.push(this.editor.btns[i]);
24203 xns: Roo.bootstrap,
24208 xns: Roo.bootstrap,
24213 cog.menu.items.push({
24215 xns: Roo.bootstrap,
24216 html : Clean styles,
24221 editorcore.insertTag(this.tagname);
24230 this.xtype = 'NavSimplebar';
24232 for(var i=0;i< children.length;i++) {
24234 this.buttons.add(this.addxtypeChild(children[i]));
24238 editor.on('editorevent', this.updateToolbar, this);
24240 onBtnClick : function(id)
24242 this.editorcore.relayCmd(id);
24243 this.editorcore.focus();
24247 * Protected method that will not generally be called directly. It triggers
24248 * a toolbar update by reading the markup state of the current selection in the editor.
24250 updateToolbar: function(){
24252 if(!this.editorcore.activated){
24253 this.editor.onFirstFocus(); // is this neeed?
24257 var btns = this.buttons;
24258 var doc = this.editorcore.doc;
24259 btns.get('bold').setActive(doc.queryCommandState('bold'));
24260 btns.get('italic').setActive(doc.queryCommandState('italic'));
24261 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24263 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24264 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24265 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24267 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24268 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24271 var ans = this.editorcore.getAllAncestors();
24272 if (this.formatCombo) {
24275 var store = this.formatCombo.store;
24276 this.formatCombo.setValue("");
24277 for (var i =0; i < ans.length;i++) {
24278 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24280 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24288 // hides menus... - so this cant be on a menu...
24289 Roo.bootstrap.MenuMgr.hideAll();
24291 Roo.bootstrap.MenuMgr.hideAll();
24292 //this.editorsyncValue();
24294 onFirstFocus: function() {
24295 this.buttons.each(function(item){
24299 toggleSourceEdit : function(sourceEditMode){
24302 if(sourceEditMode){
24303 Roo.log("disabling buttons");
24304 this.buttons.each( function(item){
24305 if(item.cmd != 'pencil'){
24311 Roo.log("enabling buttons");
24312 if(this.editorcore.initialized){
24313 this.buttons.each( function(item){
24319 Roo.log("calling toggole on editor");
24320 // tell the editor that it's been pressed..
24321 this.editor.toggleSourceEdit(sourceEditMode);
24331 * @class Roo.bootstrap.Table.AbstractSelectionModel
24332 * @extends Roo.util.Observable
24333 * Abstract base class for grid SelectionModels. It provides the interface that should be
24334 * implemented by descendant classes. This class should not be directly instantiated.
24337 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24338 this.locked = false;
24339 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24343 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24344 /** @ignore Called by the grid automatically. Do not call directly. */
24345 init : function(grid){
24351 * Locks the selections.
24354 this.locked = true;
24358 * Unlocks the selections.
24360 unlock : function(){
24361 this.locked = false;
24365 * Returns true if the selections are locked.
24366 * @return {Boolean}
24368 isLocked : function(){
24369 return this.locked;
24373 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24374 * @class Roo.bootstrap.Table.RowSelectionModel
24375 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24376 * It supports multiple selections and keyboard selection/navigation.
24378 * @param {Object} config
24381 Roo.bootstrap.Table.RowSelectionModel = function(config){
24382 Roo.apply(this, config);
24383 this.selections = new Roo.util.MixedCollection(false, function(o){
24388 this.lastActive = false;
24392 * @event selectionchange
24393 * Fires when the selection changes
24394 * @param {SelectionModel} this
24396 "selectionchange" : true,
24398 * @event afterselectionchange
24399 * Fires after the selection changes (eg. by key press or clicking)
24400 * @param {SelectionModel} this
24402 "afterselectionchange" : true,
24404 * @event beforerowselect
24405 * Fires when a row is selected being selected, return false to cancel.
24406 * @param {SelectionModel} this
24407 * @param {Number} rowIndex The selected index
24408 * @param {Boolean} keepExisting False if other selections will be cleared
24410 "beforerowselect" : true,
24413 * Fires when a row is selected.
24414 * @param {SelectionModel} this
24415 * @param {Number} rowIndex The selected index
24416 * @param {Roo.data.Record} r The record
24418 "rowselect" : true,
24420 * @event rowdeselect
24421 * Fires when a row is deselected.
24422 * @param {SelectionModel} this
24423 * @param {Number} rowIndex The selected index
24425 "rowdeselect" : true
24427 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24428 this.locked = false;
24431 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24433 * @cfg {Boolean} singleSelect
24434 * True to allow selection of only one row at a time (defaults to false)
24436 singleSelect : false,
24439 initEvents : function()
24442 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24443 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24444 //}else{ // allow click to work like normal
24445 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24447 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24448 this.grid.on("rowclick", this.handleMouseDown, this);
24450 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24451 "up" : function(e){
24453 this.selectPrevious(e.shiftKey);
24454 }else if(this.last !== false && this.lastActive !== false){
24455 var last = this.last;
24456 this.selectRange(this.last, this.lastActive-1);
24457 this.grid.getView().focusRow(this.lastActive);
24458 if(last !== false){
24462 this.selectFirstRow();
24464 this.fireEvent("afterselectionchange", this);
24466 "down" : function(e){
24468 this.selectNext(e.shiftKey);
24469 }else if(this.last !== false && this.lastActive !== false){
24470 var last = this.last;
24471 this.selectRange(this.last, this.lastActive+1);
24472 this.grid.getView().focusRow(this.lastActive);
24473 if(last !== false){
24477 this.selectFirstRow();
24479 this.fireEvent("afterselectionchange", this);
24483 this.grid.store.on('load', function(){
24484 this.selections.clear();
24487 var view = this.grid.view;
24488 view.on("refresh", this.onRefresh, this);
24489 view.on("rowupdated", this.onRowUpdated, this);
24490 view.on("rowremoved", this.onRemove, this);
24495 onRefresh : function()
24497 var ds = this.grid.store, i, v = this.grid.view;
24498 var s = this.selections;
24499 s.each(function(r){
24500 if((i = ds.indexOfId(r.id)) != -1){
24509 onRemove : function(v, index, r){
24510 this.selections.remove(r);
24514 onRowUpdated : function(v, index, r){
24515 if(this.isSelected(r)){
24516 v.onRowSelect(index);
24522 * @param {Array} records The records to select
24523 * @param {Boolean} keepExisting (optional) True to keep existing selections
24525 selectRecords : function(records, keepExisting)
24528 this.clearSelections();
24530 var ds = this.grid.store;
24531 for(var i = 0, len = records.length; i < len; i++){
24532 this.selectRow(ds.indexOf(records[i]), true);
24537 * Gets the number of selected rows.
24540 getCount : function(){
24541 return this.selections.length;
24545 * Selects the first row in the grid.
24547 selectFirstRow : function(){
24552 * Select the last row.
24553 * @param {Boolean} keepExisting (optional) True to keep existing selections
24555 selectLastRow : function(keepExisting){
24556 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24557 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24561 * Selects the row immediately following the last selected row.
24562 * @param {Boolean} keepExisting (optional) True to keep existing selections
24564 selectNext : function(keepExisting)
24566 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24567 this.selectRow(this.last+1, keepExisting);
24568 this.grid.getView().focusRow(this.last);
24573 * Selects the row that precedes the last selected row.
24574 * @param {Boolean} keepExisting (optional) True to keep existing selections
24576 selectPrevious : function(keepExisting){
24578 this.selectRow(this.last-1, keepExisting);
24579 this.grid.getView().focusRow(this.last);
24584 * Returns the selected records
24585 * @return {Array} Array of selected records
24587 getSelections : function(){
24588 return [].concat(this.selections.items);
24592 * Returns the first selected record.
24595 getSelected : function(){
24596 return this.selections.itemAt(0);
24601 * Clears all selections.
24603 clearSelections : function(fast)
24609 var ds = this.grid.store;
24610 var s = this.selections;
24611 s.each(function(r){
24612 this.deselectRow(ds.indexOfId(r.id));
24616 this.selections.clear();
24623 * Selects all rows.
24625 selectAll : function(){
24629 this.selections.clear();
24630 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24631 this.selectRow(i, true);
24636 * Returns True if there is a selection.
24637 * @return {Boolean}
24639 hasSelection : function(){
24640 return this.selections.length > 0;
24644 * Returns True if the specified row is selected.
24645 * @param {Number/Record} record The record or index of the record to check
24646 * @return {Boolean}
24648 isSelected : function(index){
24649 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24650 return (r && this.selections.key(r.id) ? true : false);
24654 * Returns True if the specified record id is selected.
24655 * @param {String} id The id of record to check
24656 * @return {Boolean}
24658 isIdSelected : function(id){
24659 return (this.selections.key(id) ? true : false);
24664 handleMouseDBClick : function(e, t){
24668 handleMouseDown : function(e, t)
24670 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24671 if(this.isLocked() || rowIndex < 0 ){
24674 if(e.shiftKey && this.last !== false){
24675 var last = this.last;
24676 this.selectRange(last, rowIndex, e.ctrlKey);
24677 this.last = last; // reset the last
24681 var isSelected = this.isSelected(rowIndex);
24682 //Roo.log("select row:" + rowIndex);
24684 this.deselectRow(rowIndex);
24686 this.selectRow(rowIndex, true);
24690 if(e.button !== 0 && isSelected){
24691 alert('rowIndex 2: ' + rowIndex);
24692 view.focusRow(rowIndex);
24693 }else if(e.ctrlKey && isSelected){
24694 this.deselectRow(rowIndex);
24695 }else if(!isSelected){
24696 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24697 view.focusRow(rowIndex);
24701 this.fireEvent("afterselectionchange", this);
24704 handleDragableRowClick : function(grid, rowIndex, e)
24706 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24707 this.selectRow(rowIndex, false);
24708 grid.view.focusRow(rowIndex);
24709 this.fireEvent("afterselectionchange", this);
24714 * Selects multiple rows.
24715 * @param {Array} rows Array of the indexes of the row to select
24716 * @param {Boolean} keepExisting (optional) True to keep existing selections
24718 selectRows : function(rows, keepExisting){
24720 this.clearSelections();
24722 for(var i = 0, len = rows.length; i < len; i++){
24723 this.selectRow(rows[i], true);
24728 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24729 * @param {Number} startRow The index of the first row in the range
24730 * @param {Number} endRow The index of the last row in the range
24731 * @param {Boolean} keepExisting (optional) True to retain existing selections
24733 selectRange : function(startRow, endRow, keepExisting){
24738 this.clearSelections();
24740 if(startRow <= endRow){
24741 for(var i = startRow; i <= endRow; i++){
24742 this.selectRow(i, true);
24745 for(var i = startRow; i >= endRow; i--){
24746 this.selectRow(i, true);
24752 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24753 * @param {Number} startRow The index of the first row in the range
24754 * @param {Number} endRow The index of the last row in the range
24756 deselectRange : function(startRow, endRow, preventViewNotify){
24760 for(var i = startRow; i <= endRow; i++){
24761 this.deselectRow(i, preventViewNotify);
24767 * @param {Number} row The index of the row to select
24768 * @param {Boolean} keepExisting (optional) True to keep existing selections
24770 selectRow : function(index, keepExisting, preventViewNotify)
24772 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24775 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24776 if(!keepExisting || this.singleSelect){
24777 this.clearSelections();
24780 var r = this.grid.store.getAt(index);
24781 //console.log('selectRow - record id :' + r.id);
24783 this.selections.add(r);
24784 this.last = this.lastActive = index;
24785 if(!preventViewNotify){
24786 var proxy = new Roo.Element(
24787 this.grid.getRowDom(index)
24789 proxy.addClass('bg-info info');
24791 this.fireEvent("rowselect", this, index, r);
24792 this.fireEvent("selectionchange", this);
24798 * @param {Number} row The index of the row to deselect
24800 deselectRow : function(index, preventViewNotify)
24805 if(this.last == index){
24808 if(this.lastActive == index){
24809 this.lastActive = false;
24812 var r = this.grid.store.getAt(index);
24817 this.selections.remove(r);
24818 //.console.log('deselectRow - record id :' + r.id);
24819 if(!preventViewNotify){
24821 var proxy = new Roo.Element(
24822 this.grid.getRowDom(index)
24824 proxy.removeClass('bg-info info');
24826 this.fireEvent("rowdeselect", this, index);
24827 this.fireEvent("selectionchange", this);
24831 restoreLast : function(){
24833 this.last = this._last;
24838 acceptsNav : function(row, col, cm){
24839 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24843 onEditorKey : function(field, e){
24844 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24849 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24851 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24853 }else if(k == e.ENTER && !e.ctrlKey){
24857 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24859 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24861 }else if(k == e.ESC){
24865 g.startEditing(newCell[0], newCell[1]);
24871 * Ext JS Library 1.1.1
24872 * Copyright(c) 2006-2007, Ext JS, LLC.
24874 * Originally Released Under LGPL - original licence link has changed is not relivant.
24877 * <script type="text/javascript">
24881 * @class Roo.bootstrap.PagingToolbar
24882 * @extends Roo.bootstrap.NavSimplebar
24883 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24885 * Create a new PagingToolbar
24886 * @param {Object} config The config object
24887 * @param {Roo.data.Store} store
24889 Roo.bootstrap.PagingToolbar = function(config)
24891 // old args format still supported... - xtype is prefered..
24892 // created from xtype...
24894 this.ds = config.dataSource;
24896 if (config.store && !this.ds) {
24897 this.store= Roo.factory(config.store, Roo.data);
24898 this.ds = this.store;
24899 this.ds.xmodule = this.xmodule || false;
24902 this.toolbarItems = [];
24903 if (config.items) {
24904 this.toolbarItems = config.items;
24907 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24912 this.bind(this.ds);
24915 if (Roo.bootstrap.version == 4) {
24916 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24918 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24923 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24925 * @cfg {Roo.data.Store} dataSource
24926 * The underlying data store providing the paged data
24929 * @cfg {String/HTMLElement/Element} container
24930 * container The id or element that will contain the toolbar
24933 * @cfg {Boolean} displayInfo
24934 * True to display the displayMsg (defaults to false)
24937 * @cfg {Number} pageSize
24938 * The number of records to display per page (defaults to 20)
24942 * @cfg {String} displayMsg
24943 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24945 displayMsg : 'Displaying {0} - {1} of {2}',
24947 * @cfg {String} emptyMsg
24948 * The message to display when no records are found (defaults to "No data to display")
24950 emptyMsg : 'No data to display',
24952 * Customizable piece of the default paging text (defaults to "Page")
24955 beforePageText : "Page",
24957 * Customizable piece of the default paging text (defaults to "of %0")
24960 afterPageText : "of {0}",
24962 * Customizable piece of the default paging text (defaults to "First Page")
24965 firstText : "First Page",
24967 * Customizable piece of the default paging text (defaults to "Previous Page")
24970 prevText : "Previous Page",
24972 * Customizable piece of the default paging text (defaults to "Next Page")
24975 nextText : "Next Page",
24977 * Customizable piece of the default paging text (defaults to "Last Page")
24980 lastText : "Last Page",
24982 * Customizable piece of the default paging text (defaults to "Refresh")
24985 refreshText : "Refresh",
24989 onRender : function(ct, position)
24991 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24992 this.navgroup.parentId = this.id;
24993 this.navgroup.onRender(this.el, null);
24994 // add the buttons to the navgroup
24996 if(this.displayInfo){
24997 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24998 this.displayEl = this.el.select('.x-paging-info', true).first();
24999 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
25000 // this.displayEl = navel.el.select('span',true).first();
25006 Roo.each(_this.buttons, function(e){ // this might need to use render????
25007 Roo.factory(e).render(_this.el);
25011 Roo.each(_this.toolbarItems, function(e) {
25012 _this.navgroup.addItem(e);
25016 this.first = this.navgroup.addItem({
25017 tooltip: this.firstText,
25018 cls: "prev btn-outline-secondary",
25019 html : ' <i class="fa fa-step-backward"></i>',
25021 preventDefault: true,
25022 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25025 this.prev = this.navgroup.addItem({
25026 tooltip: this.prevText,
25027 cls: "prev btn-outline-secondary",
25028 html : ' <i class="fa fa-backward"></i>',
25030 preventDefault: true,
25031 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25033 //this.addSeparator();
25036 var field = this.navgroup.addItem( {
25038 cls : 'x-paging-position btn-outline-secondary',
25040 html : this.beforePageText +
25041 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25042 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25045 this.field = field.el.select('input', true).first();
25046 this.field.on("keydown", this.onPagingKeydown, this);
25047 this.field.on("focus", function(){this.dom.select();});
25050 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25051 //this.field.setHeight(18);
25052 //this.addSeparator();
25053 this.next = this.navgroup.addItem({
25054 tooltip: this.nextText,
25055 cls: "next btn-outline-secondary",
25056 html : ' <i class="fa fa-forward"></i>',
25058 preventDefault: true,
25059 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25061 this.last = this.navgroup.addItem({
25062 tooltip: this.lastText,
25063 html : ' <i class="fa fa-step-forward"></i>',
25064 cls: "next btn-outline-secondary",
25066 preventDefault: true,
25067 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25069 //this.addSeparator();
25070 this.loading = this.navgroup.addItem({
25071 tooltip: this.refreshText,
25072 cls: "btn-outline-secondary",
25073 html : ' <i class="fa fa-refresh"></i>',
25074 preventDefault: true,
25075 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25081 updateInfo : function(){
25082 if(this.displayEl){
25083 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25084 var msg = count == 0 ?
25088 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25090 this.displayEl.update(msg);
25095 onLoad : function(ds, r, o)
25097 this.cursor = o.params.start ? o.params.start : 0;
25099 var d = this.getPageData(),
25104 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25105 this.field.dom.value = ap;
25106 this.first.setDisabled(ap == 1);
25107 this.prev.setDisabled(ap == 1);
25108 this.next.setDisabled(ap == ps);
25109 this.last.setDisabled(ap == ps);
25110 this.loading.enable();
25115 getPageData : function(){
25116 var total = this.ds.getTotalCount();
25119 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25120 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25125 onLoadError : function(){
25126 this.loading.enable();
25130 onPagingKeydown : function(e){
25131 var k = e.getKey();
25132 var d = this.getPageData();
25134 var v = this.field.dom.value, pageNum;
25135 if(!v || isNaN(pageNum = parseInt(v, 10))){
25136 this.field.dom.value = d.activePage;
25139 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25140 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25143 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))
25145 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25146 this.field.dom.value = pageNum;
25147 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25150 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25152 var v = this.field.dom.value, pageNum;
25153 var increment = (e.shiftKey) ? 10 : 1;
25154 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25157 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25158 this.field.dom.value = d.activePage;
25161 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25163 this.field.dom.value = parseInt(v, 10) + increment;
25164 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25165 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25172 beforeLoad : function(){
25174 this.loading.disable();
25179 onClick : function(which){
25188 ds.load({params:{start: 0, limit: this.pageSize}});
25191 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25194 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25197 var total = ds.getTotalCount();
25198 var extra = total % this.pageSize;
25199 var lastStart = extra ? (total - extra) : total-this.pageSize;
25200 ds.load({params:{start: lastStart, limit: this.pageSize}});
25203 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25209 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25210 * @param {Roo.data.Store} store The data store to unbind
25212 unbind : function(ds){
25213 ds.un("beforeload", this.beforeLoad, this);
25214 ds.un("load", this.onLoad, this);
25215 ds.un("loadexception", this.onLoadError, this);
25216 ds.un("remove", this.updateInfo, this);
25217 ds.un("add", this.updateInfo, this);
25218 this.ds = undefined;
25222 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25223 * @param {Roo.data.Store} store The data store to bind
25225 bind : function(ds){
25226 ds.on("beforeload", this.beforeLoad, this);
25227 ds.on("load", this.onLoad, this);
25228 ds.on("loadexception", this.onLoadError, this);
25229 ds.on("remove", this.updateInfo, this);
25230 ds.on("add", this.updateInfo, this);
25241 * @class Roo.bootstrap.MessageBar
25242 * @extends Roo.bootstrap.Component
25243 * Bootstrap MessageBar class
25244 * @cfg {String} html contents of the MessageBar
25245 * @cfg {String} weight (info | success | warning | danger) default info
25246 * @cfg {String} beforeClass insert the bar before the given class
25247 * @cfg {Boolean} closable (true | false) default false
25248 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25251 * Create a new Element
25252 * @param {Object} config The config object
25255 Roo.bootstrap.MessageBar = function(config){
25256 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25259 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25265 beforeClass: 'bootstrap-sticky-wrap',
25267 getAutoCreate : function(){
25271 cls: 'alert alert-dismissable alert-' + this.weight,
25276 html: this.html || ''
25282 cfg.cls += ' alert-messages-fixed';
25296 onRender : function(ct, position)
25298 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25301 var cfg = Roo.apply({}, this.getAutoCreate());
25305 cfg.cls += ' ' + this.cls;
25308 cfg.style = this.style;
25310 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25312 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25315 this.el.select('>button.close').on('click', this.hide, this);
25321 if (!this.rendered) {
25327 this.fireEvent('show', this);
25333 if (!this.rendered) {
25339 this.fireEvent('hide', this);
25342 update : function()
25344 // var e = this.el.dom.firstChild;
25346 // if(this.closable){
25347 // e = e.nextSibling;
25350 // e.data = this.html || '';
25352 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25368 * @class Roo.bootstrap.Graph
25369 * @extends Roo.bootstrap.Component
25370 * Bootstrap Graph class
25374 @cfg {String} graphtype bar | vbar | pie
25375 @cfg {number} g_x coodinator | centre x (pie)
25376 @cfg {number} g_y coodinator | centre y (pie)
25377 @cfg {number} g_r radius (pie)
25378 @cfg {number} g_height height of the chart (respected by all elements in the set)
25379 @cfg {number} g_width width of the chart (respected by all elements in the set)
25380 @cfg {Object} title The title of the chart
25383 -opts (object) options for the chart
25385 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25386 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25388 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.
25389 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25391 o stretch (boolean)
25393 -opts (object) options for the pie
25396 o startAngle (number)
25397 o endAngle (number)
25401 * Create a new Input
25402 * @param {Object} config The config object
25405 Roo.bootstrap.Graph = function(config){
25406 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25412 * The img click event for the img.
25413 * @param {Roo.EventObject} e
25419 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25430 //g_colors: this.colors,
25437 getAutoCreate : function(){
25448 onRender : function(ct,position){
25451 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25453 if (typeof(Raphael) == 'undefined') {
25454 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25458 this.raphael = Raphael(this.el.dom);
25460 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25461 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25462 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25463 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25465 r.text(160, 10, "Single Series Chart").attr(txtattr);
25466 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25467 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25468 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25470 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25471 r.barchart(330, 10, 300, 220, data1);
25472 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25473 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25476 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25477 // r.barchart(30, 30, 560, 250, xdata, {
25478 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25479 // axis : "0 0 1 1",
25480 // axisxlabels : xdata
25481 // //yvalues : cols,
25484 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25486 // this.load(null,xdata,{
25487 // axis : "0 0 1 1",
25488 // axisxlabels : xdata
25493 load : function(graphtype,xdata,opts)
25495 this.raphael.clear();
25497 graphtype = this.graphtype;
25502 var r = this.raphael,
25503 fin = function () {
25504 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25506 fout = function () {
25507 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25509 pfin = function() {
25510 this.sector.stop();
25511 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25514 this.label[0].stop();
25515 this.label[0].attr({ r: 7.5 });
25516 this.label[1].attr({ "font-weight": 800 });
25519 pfout = function() {
25520 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25523 this.label[0].animate({ r: 5 }, 500, "bounce");
25524 this.label[1].attr({ "font-weight": 400 });
25530 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25533 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25536 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25537 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25539 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25546 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25551 setTitle: function(o)
25556 initEvents: function() {
25559 this.el.on('click', this.onClick, this);
25563 onClick : function(e)
25565 Roo.log('img onclick');
25566 this.fireEvent('click', this, e);
25578 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25581 * @class Roo.bootstrap.dash.NumberBox
25582 * @extends Roo.bootstrap.Component
25583 * Bootstrap NumberBox class
25584 * @cfg {String} headline Box headline
25585 * @cfg {String} content Box content
25586 * @cfg {String} icon Box icon
25587 * @cfg {String} footer Footer text
25588 * @cfg {String} fhref Footer href
25591 * Create a new NumberBox
25592 * @param {Object} config The config object
25596 Roo.bootstrap.dash.NumberBox = function(config){
25597 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25601 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25610 getAutoCreate : function(){
25614 cls : 'small-box ',
25622 cls : 'roo-headline',
25623 html : this.headline
25627 cls : 'roo-content',
25628 html : this.content
25642 cls : 'ion ' + this.icon
25651 cls : 'small-box-footer',
25652 href : this.fhref || '#',
25656 cfg.cn.push(footer);
25663 onRender : function(ct,position){
25664 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25671 setHeadline: function (value)
25673 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25676 setFooter: function (value, href)
25678 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25681 this.el.select('a.small-box-footer',true).first().attr('href', href);
25686 setContent: function (value)
25688 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25691 initEvents: function()
25705 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25708 * @class Roo.bootstrap.dash.TabBox
25709 * @extends Roo.bootstrap.Component
25710 * Bootstrap TabBox class
25711 * @cfg {String} title Title of the TabBox
25712 * @cfg {String} icon Icon of the TabBox
25713 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25714 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25717 * Create a new TabBox
25718 * @param {Object} config The config object
25722 Roo.bootstrap.dash.TabBox = function(config){
25723 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25728 * When a pane is added
25729 * @param {Roo.bootstrap.dash.TabPane} pane
25733 * @event activatepane
25734 * When a pane is activated
25735 * @param {Roo.bootstrap.dash.TabPane} pane
25737 "activatepane" : true
25745 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25750 tabScrollable : false,
25752 getChildContainer : function()
25754 return this.el.select('.tab-content', true).first();
25757 getAutoCreate : function(){
25761 cls: 'pull-left header',
25769 cls: 'fa ' + this.icon
25775 cls: 'nav nav-tabs pull-right',
25781 if(this.tabScrollable){
25788 cls: 'nav nav-tabs pull-right',
25799 cls: 'nav-tabs-custom',
25804 cls: 'tab-content no-padding',
25812 initEvents : function()
25814 //Roo.log('add add pane handler');
25815 this.on('addpane', this.onAddPane, this);
25818 * Updates the box title
25819 * @param {String} html to set the title to.
25821 setTitle : function(value)
25823 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25825 onAddPane : function(pane)
25827 this.panes.push(pane);
25828 //Roo.log('addpane');
25830 // tabs are rendere left to right..
25831 if(!this.showtabs){
25835 var ctr = this.el.select('.nav-tabs', true).first();
25838 var existing = ctr.select('.nav-tab',true);
25839 var qty = existing.getCount();;
25842 var tab = ctr.createChild({
25844 cls : 'nav-tab' + (qty ? '' : ' active'),
25852 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25855 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25857 pane.el.addClass('active');
25862 onTabClick : function(ev,un,ob,pane)
25864 //Roo.log('tab - prev default');
25865 ev.preventDefault();
25868 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25869 pane.tab.addClass('active');
25870 //Roo.log(pane.title);
25871 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25872 // technically we should have a deactivate event.. but maybe add later.
25873 // and it should not de-activate the selected tab...
25874 this.fireEvent('activatepane', pane);
25875 pane.el.addClass('active');
25876 pane.fireEvent('activate');
25881 getActivePane : function()
25884 Roo.each(this.panes, function(p) {
25885 if(p.el.hasClass('active')){
25906 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25908 * @class Roo.bootstrap.TabPane
25909 * @extends Roo.bootstrap.Component
25910 * Bootstrap TabPane class
25911 * @cfg {Boolean} active (false | true) Default false
25912 * @cfg {String} title title of panel
25916 * Create a new TabPane
25917 * @param {Object} config The config object
25920 Roo.bootstrap.dash.TabPane = function(config){
25921 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25927 * When a pane is activated
25928 * @param {Roo.bootstrap.dash.TabPane} pane
25935 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25940 // the tabBox that this is attached to.
25943 getAutoCreate : function()
25951 cfg.cls += ' active';
25956 initEvents : function()
25958 //Roo.log('trigger add pane handler');
25959 this.parent().fireEvent('addpane', this)
25963 * Updates the tab title
25964 * @param {String} html to set the title to.
25966 setTitle: function(str)
25972 this.tab.select('a', true).first().dom.innerHTML = str;
25989 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25992 * @class Roo.bootstrap.menu.Menu
25993 * @extends Roo.bootstrap.Component
25994 * Bootstrap Menu class - container for Menu
25995 * @cfg {String} html Text of the menu
25996 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25997 * @cfg {String} icon Font awesome icon
25998 * @cfg {String} pos Menu align to (top | bottom) default bottom
26002 * Create a new Menu
26003 * @param {Object} config The config object
26007 Roo.bootstrap.menu.Menu = function(config){
26008 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26012 * @event beforeshow
26013 * Fires before this menu is displayed
26014 * @param {Roo.bootstrap.menu.Menu} this
26018 * @event beforehide
26019 * Fires before this menu is hidden
26020 * @param {Roo.bootstrap.menu.Menu} this
26025 * Fires after this menu is displayed
26026 * @param {Roo.bootstrap.menu.Menu} this
26031 * Fires after this menu is hidden
26032 * @param {Roo.bootstrap.menu.Menu} this
26037 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26038 * @param {Roo.bootstrap.menu.Menu} this
26039 * @param {Roo.EventObject} e
26046 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26050 weight : 'default',
26055 getChildContainer : function() {
26056 if(this.isSubMenu){
26060 return this.el.select('ul.dropdown-menu', true).first();
26063 getAutoCreate : function()
26068 cls : 'roo-menu-text',
26076 cls : 'fa ' + this.icon
26087 cls : 'dropdown-button btn btn-' + this.weight,
26092 cls : 'dropdown-toggle btn btn-' + this.weight,
26102 cls : 'dropdown-menu'
26108 if(this.pos == 'top'){
26109 cfg.cls += ' dropup';
26112 if(this.isSubMenu){
26115 cls : 'dropdown-menu'
26122 onRender : function(ct, position)
26124 this.isSubMenu = ct.hasClass('dropdown-submenu');
26126 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26129 initEvents : function()
26131 if(this.isSubMenu){
26135 this.hidden = true;
26137 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26138 this.triggerEl.on('click', this.onTriggerPress, this);
26140 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26141 this.buttonEl.on('click', this.onClick, this);
26147 if(this.isSubMenu){
26151 return this.el.select('ul.dropdown-menu', true).first();
26154 onClick : function(e)
26156 this.fireEvent("click", this, e);
26159 onTriggerPress : function(e)
26161 if (this.isVisible()) {
26168 isVisible : function(){
26169 return !this.hidden;
26174 this.fireEvent("beforeshow", this);
26176 this.hidden = false;
26177 this.el.addClass('open');
26179 Roo.get(document).on("mouseup", this.onMouseUp, this);
26181 this.fireEvent("show", this);
26188 this.fireEvent("beforehide", this);
26190 this.hidden = true;
26191 this.el.removeClass('open');
26193 Roo.get(document).un("mouseup", this.onMouseUp);
26195 this.fireEvent("hide", this);
26198 onMouseUp : function()
26212 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26215 * @class Roo.bootstrap.menu.Item
26216 * @extends Roo.bootstrap.Component
26217 * Bootstrap MenuItem class
26218 * @cfg {Boolean} submenu (true | false) default false
26219 * @cfg {String} html text of the item
26220 * @cfg {String} href the link
26221 * @cfg {Boolean} disable (true | false) default false
26222 * @cfg {Boolean} preventDefault (true | false) default true
26223 * @cfg {String} icon Font awesome icon
26224 * @cfg {String} pos Submenu align to (left | right) default right
26228 * Create a new Item
26229 * @param {Object} config The config object
26233 Roo.bootstrap.menu.Item = function(config){
26234 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26238 * Fires when the mouse is hovering over this menu
26239 * @param {Roo.bootstrap.menu.Item} this
26240 * @param {Roo.EventObject} e
26245 * Fires when the mouse exits this menu
26246 * @param {Roo.bootstrap.menu.Item} this
26247 * @param {Roo.EventObject} e
26253 * The raw click event for the entire grid.
26254 * @param {Roo.EventObject} e
26260 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26265 preventDefault: true,
26270 getAutoCreate : function()
26275 cls : 'roo-menu-item-text',
26283 cls : 'fa ' + this.icon
26292 href : this.href || '#',
26299 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26303 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26305 if(this.pos == 'left'){
26306 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26313 initEvents : function()
26315 this.el.on('mouseover', this.onMouseOver, this);
26316 this.el.on('mouseout', this.onMouseOut, this);
26318 this.el.select('a', true).first().on('click', this.onClick, this);
26322 onClick : function(e)
26324 if(this.preventDefault){
26325 e.preventDefault();
26328 this.fireEvent("click", this, e);
26331 onMouseOver : function(e)
26333 if(this.submenu && this.pos == 'left'){
26334 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26337 this.fireEvent("mouseover", this, e);
26340 onMouseOut : function(e)
26342 this.fireEvent("mouseout", this, e);
26354 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26357 * @class Roo.bootstrap.menu.Separator
26358 * @extends Roo.bootstrap.Component
26359 * Bootstrap Separator class
26362 * Create a new Separator
26363 * @param {Object} config The config object
26367 Roo.bootstrap.menu.Separator = function(config){
26368 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26371 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26373 getAutoCreate : function(){
26394 * @class Roo.bootstrap.Tooltip
26395 * Bootstrap Tooltip class
26396 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26397 * to determine which dom element triggers the tooltip.
26399 * It needs to add support for additional attributes like tooltip-position
26402 * Create a new Toolti
26403 * @param {Object} config The config object
26406 Roo.bootstrap.Tooltip = function(config){
26407 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26409 this.alignment = Roo.bootstrap.Tooltip.alignment;
26411 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26412 this.alignment = config.alignment;
26417 Roo.apply(Roo.bootstrap.Tooltip, {
26419 * @function init initialize tooltip monitoring.
26423 currentTip : false,
26424 currentRegion : false,
26430 Roo.get(document).on('mouseover', this.enter ,this);
26431 Roo.get(document).on('mouseout', this.leave, this);
26434 this.currentTip = new Roo.bootstrap.Tooltip();
26437 enter : function(ev)
26439 var dom = ev.getTarget();
26441 //Roo.log(['enter',dom]);
26442 var el = Roo.fly(dom);
26443 if (this.currentEl) {
26445 //Roo.log(this.currentEl);
26446 //Roo.log(this.currentEl.contains(dom));
26447 if (this.currentEl == el) {
26450 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26456 if (this.currentTip.el) {
26457 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26461 if(!el || el.dom == document){
26467 // you can not look for children, as if el is the body.. then everythign is the child..
26468 if (!el.attr('tooltip')) { //
26469 if (!el.select("[tooltip]").elements.length) {
26472 // is the mouse over this child...?
26473 bindEl = el.select("[tooltip]").first();
26474 var xy = ev.getXY();
26475 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26476 //Roo.log("not in region.");
26479 //Roo.log("child element over..");
26482 this.currentEl = bindEl;
26483 this.currentTip.bind(bindEl);
26484 this.currentRegion = Roo.lib.Region.getRegion(dom);
26485 this.currentTip.enter();
26488 leave : function(ev)
26490 var dom = ev.getTarget();
26491 //Roo.log(['leave',dom]);
26492 if (!this.currentEl) {
26497 if (dom != this.currentEl.dom) {
26500 var xy = ev.getXY();
26501 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26504 // only activate leave if mouse cursor is outside... bounding box..
26509 if (this.currentTip) {
26510 this.currentTip.leave();
26512 //Roo.log('clear currentEl');
26513 this.currentEl = false;
26518 'left' : ['r-l', [-2,0], 'right'],
26519 'right' : ['l-r', [2,0], 'left'],
26520 'bottom' : ['t-b', [0,2], 'top'],
26521 'top' : [ 'b-t', [0,-2], 'bottom']
26527 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26532 delay : null, // can be { show : 300 , hide: 500}
26536 hoverState : null, //???
26538 placement : 'bottom',
26542 getAutoCreate : function(){
26549 cls : 'tooltip-arrow'
26552 cls : 'tooltip-inner'
26559 bind : function(el)
26565 enter : function () {
26567 if (this.timeout != null) {
26568 clearTimeout(this.timeout);
26571 this.hoverState = 'in';
26572 //Roo.log("enter - show");
26573 if (!this.delay || !this.delay.show) {
26578 this.timeout = setTimeout(function () {
26579 if (_t.hoverState == 'in') {
26582 }, this.delay.show);
26586 clearTimeout(this.timeout);
26588 this.hoverState = 'out';
26589 if (!this.delay || !this.delay.hide) {
26595 this.timeout = setTimeout(function () {
26596 //Roo.log("leave - timeout");
26598 if (_t.hoverState == 'out') {
26600 Roo.bootstrap.Tooltip.currentEl = false;
26605 show : function (msg)
26608 this.render(document.body);
26611 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26613 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26615 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26617 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26619 var placement = typeof this.placement == 'function' ?
26620 this.placement.call(this, this.el, on_el) :
26623 var autoToken = /\s?auto?\s?/i;
26624 var autoPlace = autoToken.test(placement);
26626 placement = placement.replace(autoToken, '') || 'top';
26630 //this.el.setXY([0,0]);
26632 //this.el.dom.style.display='block';
26634 //this.el.appendTo(on_el);
26636 var p = this.getPosition();
26637 var box = this.el.getBox();
26643 var align = this.alignment[placement];
26645 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26647 if(placement == 'top' || placement == 'bottom'){
26649 placement = 'right';
26652 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26653 placement = 'left';
26656 var scroll = Roo.select('body', true).first().getScroll();
26658 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26662 align = this.alignment[placement];
26665 this.el.alignTo(this.bindEl, align[0],align[1]);
26666 //var arrow = this.el.select('.arrow',true).first();
26667 //arrow.set(align[2],
26669 this.el.addClass(placement);
26671 this.el.addClass('in fade');
26673 this.hoverState = null;
26675 if (this.el.hasClass('fade')) {
26686 //this.el.setXY([0,0]);
26687 this.el.removeClass('in');
26703 * @class Roo.bootstrap.LocationPicker
26704 * @extends Roo.bootstrap.Component
26705 * Bootstrap LocationPicker class
26706 * @cfg {Number} latitude Position when init default 0
26707 * @cfg {Number} longitude Position when init default 0
26708 * @cfg {Number} zoom default 15
26709 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26710 * @cfg {Boolean} mapTypeControl default false
26711 * @cfg {Boolean} disableDoubleClickZoom default false
26712 * @cfg {Boolean} scrollwheel default true
26713 * @cfg {Boolean} streetViewControl default false
26714 * @cfg {Number} radius default 0
26715 * @cfg {String} locationName
26716 * @cfg {Boolean} draggable default true
26717 * @cfg {Boolean} enableAutocomplete default false
26718 * @cfg {Boolean} enableReverseGeocode default true
26719 * @cfg {String} markerTitle
26722 * Create a new LocationPicker
26723 * @param {Object} config The config object
26727 Roo.bootstrap.LocationPicker = function(config){
26729 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26734 * Fires when the picker initialized.
26735 * @param {Roo.bootstrap.LocationPicker} this
26736 * @param {Google Location} location
26740 * @event positionchanged
26741 * Fires when the picker position changed.
26742 * @param {Roo.bootstrap.LocationPicker} this
26743 * @param {Google Location} location
26745 positionchanged : true,
26748 * Fires when the map resize.
26749 * @param {Roo.bootstrap.LocationPicker} this
26754 * Fires when the map show.
26755 * @param {Roo.bootstrap.LocationPicker} this
26760 * Fires when the map hide.
26761 * @param {Roo.bootstrap.LocationPicker} this
26766 * Fires when click the map.
26767 * @param {Roo.bootstrap.LocationPicker} this
26768 * @param {Map event} e
26772 * @event mapRightClick
26773 * Fires when right click the map.
26774 * @param {Roo.bootstrap.LocationPicker} this
26775 * @param {Map event} e
26777 mapRightClick : true,
26779 * @event markerClick
26780 * Fires when click the marker.
26781 * @param {Roo.bootstrap.LocationPicker} this
26782 * @param {Map event} e
26784 markerClick : true,
26786 * @event markerRightClick
26787 * Fires when right click the marker.
26788 * @param {Roo.bootstrap.LocationPicker} this
26789 * @param {Map event} e
26791 markerRightClick : true,
26793 * @event OverlayViewDraw
26794 * Fires when OverlayView Draw
26795 * @param {Roo.bootstrap.LocationPicker} this
26797 OverlayViewDraw : true,
26799 * @event OverlayViewOnAdd
26800 * Fires when OverlayView Draw
26801 * @param {Roo.bootstrap.LocationPicker} this
26803 OverlayViewOnAdd : true,
26805 * @event OverlayViewOnRemove
26806 * Fires when OverlayView Draw
26807 * @param {Roo.bootstrap.LocationPicker} this
26809 OverlayViewOnRemove : true,
26811 * @event OverlayViewShow
26812 * Fires when OverlayView Draw
26813 * @param {Roo.bootstrap.LocationPicker} this
26814 * @param {Pixel} cpx
26816 OverlayViewShow : true,
26818 * @event OverlayViewHide
26819 * Fires when OverlayView Draw
26820 * @param {Roo.bootstrap.LocationPicker} this
26822 OverlayViewHide : true,
26824 * @event loadexception
26825 * Fires when load google lib failed.
26826 * @param {Roo.bootstrap.LocationPicker} this
26828 loadexception : true
26833 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26835 gMapContext: false,
26841 mapTypeControl: false,
26842 disableDoubleClickZoom: false,
26844 streetViewControl: false,
26848 enableAutocomplete: false,
26849 enableReverseGeocode: true,
26852 getAutoCreate: function()
26857 cls: 'roo-location-picker'
26863 initEvents: function(ct, position)
26865 if(!this.el.getWidth() || this.isApplied()){
26869 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26874 initial: function()
26876 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26877 this.fireEvent('loadexception', this);
26881 if(!this.mapTypeId){
26882 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26885 this.gMapContext = this.GMapContext();
26887 this.initOverlayView();
26889 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26893 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26894 _this.setPosition(_this.gMapContext.marker.position);
26897 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26898 _this.fireEvent('mapClick', this, event);
26902 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26903 _this.fireEvent('mapRightClick', this, event);
26907 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26908 _this.fireEvent('markerClick', this, event);
26912 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26913 _this.fireEvent('markerRightClick', this, event);
26917 this.setPosition(this.gMapContext.location);
26919 this.fireEvent('initial', this, this.gMapContext.location);
26922 initOverlayView: function()
26926 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26930 _this.fireEvent('OverlayViewDraw', _this);
26935 _this.fireEvent('OverlayViewOnAdd', _this);
26938 onRemove: function()
26940 _this.fireEvent('OverlayViewOnRemove', _this);
26943 show: function(cpx)
26945 _this.fireEvent('OverlayViewShow', _this, cpx);
26950 _this.fireEvent('OverlayViewHide', _this);
26956 fromLatLngToContainerPixel: function(event)
26958 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26961 isApplied: function()
26963 return this.getGmapContext() == false ? false : true;
26966 getGmapContext: function()
26968 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26971 GMapContext: function()
26973 var position = new google.maps.LatLng(this.latitude, this.longitude);
26975 var _map = new google.maps.Map(this.el.dom, {
26978 mapTypeId: this.mapTypeId,
26979 mapTypeControl: this.mapTypeControl,
26980 disableDoubleClickZoom: this.disableDoubleClickZoom,
26981 scrollwheel: this.scrollwheel,
26982 streetViewControl: this.streetViewControl,
26983 locationName: this.locationName,
26984 draggable: this.draggable,
26985 enableAutocomplete: this.enableAutocomplete,
26986 enableReverseGeocode: this.enableReverseGeocode
26989 var _marker = new google.maps.Marker({
26990 position: position,
26992 title: this.markerTitle,
26993 draggable: this.draggable
27000 location: position,
27001 radius: this.radius,
27002 locationName: this.locationName,
27003 addressComponents: {
27004 formatted_address: null,
27005 addressLine1: null,
27006 addressLine2: null,
27008 streetNumber: null,
27012 stateOrProvince: null
27015 domContainer: this.el.dom,
27016 geodecoder: new google.maps.Geocoder()
27020 drawCircle: function(center, radius, options)
27022 if (this.gMapContext.circle != null) {
27023 this.gMapContext.circle.setMap(null);
27027 options = Roo.apply({}, options, {
27028 strokeColor: "#0000FF",
27029 strokeOpacity: .35,
27031 fillColor: "#0000FF",
27035 options.map = this.gMapContext.map;
27036 options.radius = radius;
27037 options.center = center;
27038 this.gMapContext.circle = new google.maps.Circle(options);
27039 return this.gMapContext.circle;
27045 setPosition: function(location)
27047 this.gMapContext.location = location;
27048 this.gMapContext.marker.setPosition(location);
27049 this.gMapContext.map.panTo(location);
27050 this.drawCircle(location, this.gMapContext.radius, {});
27054 if (this.gMapContext.settings.enableReverseGeocode) {
27055 this.gMapContext.geodecoder.geocode({
27056 latLng: this.gMapContext.location
27057 }, function(results, status) {
27059 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27060 _this.gMapContext.locationName = results[0].formatted_address;
27061 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27063 _this.fireEvent('positionchanged', this, location);
27070 this.fireEvent('positionchanged', this, location);
27075 google.maps.event.trigger(this.gMapContext.map, "resize");
27077 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27079 this.fireEvent('resize', this);
27082 setPositionByLatLng: function(latitude, longitude)
27084 this.setPosition(new google.maps.LatLng(latitude, longitude));
27087 getCurrentPosition: function()
27090 latitude: this.gMapContext.location.lat(),
27091 longitude: this.gMapContext.location.lng()
27095 getAddressName: function()
27097 return this.gMapContext.locationName;
27100 getAddressComponents: function()
27102 return this.gMapContext.addressComponents;
27105 address_component_from_google_geocode: function(address_components)
27109 for (var i = 0; i < address_components.length; i++) {
27110 var component = address_components[i];
27111 if (component.types.indexOf("postal_code") >= 0) {
27112 result.postalCode = component.short_name;
27113 } else if (component.types.indexOf("street_number") >= 0) {
27114 result.streetNumber = component.short_name;
27115 } else if (component.types.indexOf("route") >= 0) {
27116 result.streetName = component.short_name;
27117 } else if (component.types.indexOf("neighborhood") >= 0) {
27118 result.city = component.short_name;
27119 } else if (component.types.indexOf("locality") >= 0) {
27120 result.city = component.short_name;
27121 } else if (component.types.indexOf("sublocality") >= 0) {
27122 result.district = component.short_name;
27123 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27124 result.stateOrProvince = component.short_name;
27125 } else if (component.types.indexOf("country") >= 0) {
27126 result.country = component.short_name;
27130 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27131 result.addressLine2 = "";
27135 setZoomLevel: function(zoom)
27137 this.gMapContext.map.setZoom(zoom);
27150 this.fireEvent('show', this);
27161 this.fireEvent('hide', this);
27166 Roo.apply(Roo.bootstrap.LocationPicker, {
27168 OverlayView : function(map, options)
27170 options = options || {};
27184 * @class Roo.bootstrap.Alert
27185 * @extends Roo.bootstrap.Component
27186 * Bootstrap Alert class
27187 * @cfg {String} title The title of alert
27188 * @cfg {String} html The content of alert
27189 * @cfg {String} weight ( success | info | warning | danger )
27190 * @cfg {String} faicon font-awesomeicon
27193 * Create a new alert
27194 * @param {Object} config The config object
27198 Roo.bootstrap.Alert = function(config){
27199 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27203 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27210 getAutoCreate : function()
27219 cls : 'roo-alert-icon'
27224 cls : 'roo-alert-title',
27229 cls : 'roo-alert-text',
27236 cfg.cn[0].cls += ' fa ' + this.faicon;
27240 cfg.cls += ' alert-' + this.weight;
27246 initEvents: function()
27248 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27251 setTitle : function(str)
27253 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27256 setText : function(str)
27258 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27261 setWeight : function(weight)
27264 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27267 this.weight = weight;
27269 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27272 setIcon : function(icon)
27275 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27278 this.faicon = icon;
27280 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27301 * @class Roo.bootstrap.UploadCropbox
27302 * @extends Roo.bootstrap.Component
27303 * Bootstrap UploadCropbox class
27304 * @cfg {String} emptyText show when image has been loaded
27305 * @cfg {String} rotateNotify show when image too small to rotate
27306 * @cfg {Number} errorTimeout default 3000
27307 * @cfg {Number} minWidth default 300
27308 * @cfg {Number} minHeight default 300
27309 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27310 * @cfg {Boolean} isDocument (true|false) default false
27311 * @cfg {String} url action url
27312 * @cfg {String} paramName default 'imageUpload'
27313 * @cfg {String} method default POST
27314 * @cfg {Boolean} loadMask (true|false) default true
27315 * @cfg {Boolean} loadingText default 'Loading...'
27318 * Create a new UploadCropbox
27319 * @param {Object} config The config object
27322 Roo.bootstrap.UploadCropbox = function(config){
27323 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27327 * @event beforeselectfile
27328 * Fire before select file
27329 * @param {Roo.bootstrap.UploadCropbox} this
27331 "beforeselectfile" : true,
27334 * Fire after initEvent
27335 * @param {Roo.bootstrap.UploadCropbox} this
27340 * Fire after initEvent
27341 * @param {Roo.bootstrap.UploadCropbox} this
27342 * @param {String} data
27347 * Fire when preparing the file data
27348 * @param {Roo.bootstrap.UploadCropbox} this
27349 * @param {Object} file
27354 * Fire when get exception
27355 * @param {Roo.bootstrap.UploadCropbox} this
27356 * @param {XMLHttpRequest} xhr
27358 "exception" : true,
27360 * @event beforeloadcanvas
27361 * Fire before load the canvas
27362 * @param {Roo.bootstrap.UploadCropbox} this
27363 * @param {String} src
27365 "beforeloadcanvas" : true,
27368 * Fire when trash image
27369 * @param {Roo.bootstrap.UploadCropbox} this
27374 * Fire when download the image
27375 * @param {Roo.bootstrap.UploadCropbox} this
27379 * @event footerbuttonclick
27380 * Fire when footerbuttonclick
27381 * @param {Roo.bootstrap.UploadCropbox} this
27382 * @param {String} type
27384 "footerbuttonclick" : true,
27388 * @param {Roo.bootstrap.UploadCropbox} this
27393 * Fire when rotate the image
27394 * @param {Roo.bootstrap.UploadCropbox} this
27395 * @param {String} pos
27400 * Fire when inspect the file
27401 * @param {Roo.bootstrap.UploadCropbox} this
27402 * @param {Object} file
27407 * Fire when xhr upload the file
27408 * @param {Roo.bootstrap.UploadCropbox} this
27409 * @param {Object} data
27414 * Fire when arrange the file data
27415 * @param {Roo.bootstrap.UploadCropbox} this
27416 * @param {Object} formData
27421 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27424 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27426 emptyText : 'Click to upload image',
27427 rotateNotify : 'Image is too small to rotate',
27428 errorTimeout : 3000,
27442 cropType : 'image/jpeg',
27444 canvasLoaded : false,
27445 isDocument : false,
27447 paramName : 'imageUpload',
27449 loadingText : 'Loading...',
27452 getAutoCreate : function()
27456 cls : 'roo-upload-cropbox',
27460 cls : 'roo-upload-cropbox-selector',
27465 cls : 'roo-upload-cropbox-body',
27466 style : 'cursor:pointer',
27470 cls : 'roo-upload-cropbox-preview'
27474 cls : 'roo-upload-cropbox-thumb'
27478 cls : 'roo-upload-cropbox-empty-notify',
27479 html : this.emptyText
27483 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27484 html : this.rotateNotify
27490 cls : 'roo-upload-cropbox-footer',
27493 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27503 onRender : function(ct, position)
27505 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27507 if (this.buttons.length) {
27509 Roo.each(this.buttons, function(bb) {
27511 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27513 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27519 this.maskEl = this.el;
27523 initEvents : function()
27525 this.urlAPI = (window.createObjectURL && window) ||
27526 (window.URL && URL.revokeObjectURL && URL) ||
27527 (window.webkitURL && webkitURL);
27529 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27530 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27532 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27533 this.selectorEl.hide();
27535 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27536 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27538 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27539 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27540 this.thumbEl.hide();
27542 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27543 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27545 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27546 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27547 this.errorEl.hide();
27549 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27550 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27551 this.footerEl.hide();
27553 this.setThumbBoxSize();
27559 this.fireEvent('initial', this);
27566 window.addEventListener("resize", function() { _this.resize(); } );
27568 this.bodyEl.on('click', this.beforeSelectFile, this);
27571 this.bodyEl.on('touchstart', this.onTouchStart, this);
27572 this.bodyEl.on('touchmove', this.onTouchMove, this);
27573 this.bodyEl.on('touchend', this.onTouchEnd, this);
27577 this.bodyEl.on('mousedown', this.onMouseDown, this);
27578 this.bodyEl.on('mousemove', this.onMouseMove, this);
27579 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27580 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27581 Roo.get(document).on('mouseup', this.onMouseUp, this);
27584 this.selectorEl.on('change', this.onFileSelected, this);
27590 this.baseScale = 1;
27592 this.baseRotate = 1;
27593 this.dragable = false;
27594 this.pinching = false;
27597 this.cropData = false;
27598 this.notifyEl.dom.innerHTML = this.emptyText;
27600 this.selectorEl.dom.value = '';
27604 resize : function()
27606 if(this.fireEvent('resize', this) != false){
27607 this.setThumbBoxPosition();
27608 this.setCanvasPosition();
27612 onFooterButtonClick : function(e, el, o, type)
27615 case 'rotate-left' :
27616 this.onRotateLeft(e);
27618 case 'rotate-right' :
27619 this.onRotateRight(e);
27622 this.beforeSelectFile(e);
27637 this.fireEvent('footerbuttonclick', this, type);
27640 beforeSelectFile : function(e)
27642 e.preventDefault();
27644 if(this.fireEvent('beforeselectfile', this) != false){
27645 this.selectorEl.dom.click();
27649 onFileSelected : function(e)
27651 e.preventDefault();
27653 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27657 var file = this.selectorEl.dom.files[0];
27659 if(this.fireEvent('inspect', this, file) != false){
27660 this.prepare(file);
27665 trash : function(e)
27667 this.fireEvent('trash', this);
27670 download : function(e)
27672 this.fireEvent('download', this);
27675 loadCanvas : function(src)
27677 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27681 this.imageEl = document.createElement('img');
27685 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27687 this.imageEl.src = src;
27691 onLoadCanvas : function()
27693 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27694 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27696 this.bodyEl.un('click', this.beforeSelectFile, this);
27698 this.notifyEl.hide();
27699 this.thumbEl.show();
27700 this.footerEl.show();
27702 this.baseRotateLevel();
27704 if(this.isDocument){
27705 this.setThumbBoxSize();
27708 this.setThumbBoxPosition();
27710 this.baseScaleLevel();
27716 this.canvasLoaded = true;
27719 this.maskEl.unmask();
27724 setCanvasPosition : function()
27726 if(!this.canvasEl){
27730 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27731 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27733 this.previewEl.setLeft(pw);
27734 this.previewEl.setTop(ph);
27738 onMouseDown : function(e)
27742 this.dragable = true;
27743 this.pinching = false;
27745 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27746 this.dragable = false;
27750 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27751 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27755 onMouseMove : function(e)
27759 if(!this.canvasLoaded){
27763 if (!this.dragable){
27767 var minX = Math.ceil(this.thumbEl.getLeft(true));
27768 var minY = Math.ceil(this.thumbEl.getTop(true));
27770 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27771 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27773 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27774 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27776 x = x - this.mouseX;
27777 y = y - this.mouseY;
27779 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27780 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27782 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27783 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27785 this.previewEl.setLeft(bgX);
27786 this.previewEl.setTop(bgY);
27788 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27789 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27792 onMouseUp : function(e)
27796 this.dragable = false;
27799 onMouseWheel : function(e)
27803 this.startScale = this.scale;
27805 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27807 if(!this.zoomable()){
27808 this.scale = this.startScale;
27817 zoomable : function()
27819 var minScale = this.thumbEl.getWidth() / this.minWidth;
27821 if(this.minWidth < this.minHeight){
27822 minScale = this.thumbEl.getHeight() / this.minHeight;
27825 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27826 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27830 (this.rotate == 0 || this.rotate == 180) &&
27832 width > this.imageEl.OriginWidth ||
27833 height > this.imageEl.OriginHeight ||
27834 (width < this.minWidth && height < this.minHeight)
27842 (this.rotate == 90 || this.rotate == 270) &&
27844 width > this.imageEl.OriginWidth ||
27845 height > this.imageEl.OriginHeight ||
27846 (width < this.minHeight && height < this.minWidth)
27853 !this.isDocument &&
27854 (this.rotate == 0 || this.rotate == 180) &&
27856 width < this.minWidth ||
27857 width > this.imageEl.OriginWidth ||
27858 height < this.minHeight ||
27859 height > this.imageEl.OriginHeight
27866 !this.isDocument &&
27867 (this.rotate == 90 || this.rotate == 270) &&
27869 width < this.minHeight ||
27870 width > this.imageEl.OriginWidth ||
27871 height < this.minWidth ||
27872 height > this.imageEl.OriginHeight
27882 onRotateLeft : function(e)
27884 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27886 var minScale = this.thumbEl.getWidth() / this.minWidth;
27888 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27889 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27891 this.startScale = this.scale;
27893 while (this.getScaleLevel() < minScale){
27895 this.scale = this.scale + 1;
27897 if(!this.zoomable()){
27902 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27903 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27908 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27915 this.scale = this.startScale;
27917 this.onRotateFail();
27922 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27924 if(this.isDocument){
27925 this.setThumbBoxSize();
27926 this.setThumbBoxPosition();
27927 this.setCanvasPosition();
27932 this.fireEvent('rotate', this, 'left');
27936 onRotateRight : function(e)
27938 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27940 var minScale = this.thumbEl.getWidth() / this.minWidth;
27942 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27943 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27945 this.startScale = this.scale;
27947 while (this.getScaleLevel() < minScale){
27949 this.scale = this.scale + 1;
27951 if(!this.zoomable()){
27956 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27957 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27962 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27969 this.scale = this.startScale;
27971 this.onRotateFail();
27976 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27978 if(this.isDocument){
27979 this.setThumbBoxSize();
27980 this.setThumbBoxPosition();
27981 this.setCanvasPosition();
27986 this.fireEvent('rotate', this, 'right');
27989 onRotateFail : function()
27991 this.errorEl.show(true);
27995 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
28000 this.previewEl.dom.innerHTML = '';
28002 var canvasEl = document.createElement("canvas");
28004 var contextEl = canvasEl.getContext("2d");
28006 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28007 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28008 var center = this.imageEl.OriginWidth / 2;
28010 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28011 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28012 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28013 center = this.imageEl.OriginHeight / 2;
28016 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28018 contextEl.translate(center, center);
28019 contextEl.rotate(this.rotate * Math.PI / 180);
28021 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28023 this.canvasEl = document.createElement("canvas");
28025 this.contextEl = this.canvasEl.getContext("2d");
28027 switch (this.rotate) {
28030 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28031 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28033 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28038 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28039 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28041 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28042 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);
28046 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28051 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28052 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28054 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28055 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);
28059 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);
28064 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28065 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28067 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28068 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28072 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);
28079 this.previewEl.appendChild(this.canvasEl);
28081 this.setCanvasPosition();
28086 if(!this.canvasLoaded){
28090 var imageCanvas = document.createElement("canvas");
28092 var imageContext = imageCanvas.getContext("2d");
28094 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28095 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28097 var center = imageCanvas.width / 2;
28099 imageContext.translate(center, center);
28101 imageContext.rotate(this.rotate * Math.PI / 180);
28103 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28105 var canvas = document.createElement("canvas");
28107 var context = canvas.getContext("2d");
28109 canvas.width = this.minWidth;
28110 canvas.height = this.minHeight;
28112 switch (this.rotate) {
28115 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28116 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28118 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28119 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28121 var targetWidth = this.minWidth - 2 * x;
28122 var targetHeight = this.minHeight - 2 * y;
28126 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28127 scale = targetWidth / width;
28130 if(x > 0 && y == 0){
28131 scale = targetHeight / height;
28134 if(x > 0 && y > 0){
28135 scale = targetWidth / width;
28137 if(width < height){
28138 scale = targetHeight / height;
28142 context.scale(scale, scale);
28144 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28145 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28147 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28148 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28150 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28155 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28156 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28158 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28159 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28161 var targetWidth = this.minWidth - 2 * x;
28162 var targetHeight = this.minHeight - 2 * y;
28166 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28167 scale = targetWidth / width;
28170 if(x > 0 && y == 0){
28171 scale = targetHeight / height;
28174 if(x > 0 && y > 0){
28175 scale = targetWidth / width;
28177 if(width < height){
28178 scale = targetHeight / height;
28182 context.scale(scale, scale);
28184 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28185 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28187 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28188 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28190 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28192 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28197 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28198 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28200 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28201 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28203 var targetWidth = this.minWidth - 2 * x;
28204 var targetHeight = this.minHeight - 2 * y;
28208 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28209 scale = targetWidth / width;
28212 if(x > 0 && y == 0){
28213 scale = targetHeight / height;
28216 if(x > 0 && y > 0){
28217 scale = targetWidth / width;
28219 if(width < height){
28220 scale = targetHeight / height;
28224 context.scale(scale, scale);
28226 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28227 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28229 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28230 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28232 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28233 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28235 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28240 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28241 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28243 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28244 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28246 var targetWidth = this.minWidth - 2 * x;
28247 var targetHeight = this.minHeight - 2 * y;
28251 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28252 scale = targetWidth / width;
28255 if(x > 0 && y == 0){
28256 scale = targetHeight / height;
28259 if(x > 0 && y > 0){
28260 scale = targetWidth / width;
28262 if(width < height){
28263 scale = targetHeight / height;
28267 context.scale(scale, scale);
28269 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28270 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28272 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28273 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28275 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28277 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28284 this.cropData = canvas.toDataURL(this.cropType);
28286 if(this.fireEvent('crop', this, this.cropData) !== false){
28287 this.process(this.file, this.cropData);
28294 setThumbBoxSize : function()
28298 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28299 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28300 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28302 this.minWidth = width;
28303 this.minHeight = height;
28305 if(this.rotate == 90 || this.rotate == 270){
28306 this.minWidth = height;
28307 this.minHeight = width;
28312 width = Math.ceil(this.minWidth * height / this.minHeight);
28314 if(this.minWidth > this.minHeight){
28316 height = Math.ceil(this.minHeight * width / this.minWidth);
28319 this.thumbEl.setStyle({
28320 width : width + 'px',
28321 height : height + 'px'
28328 setThumbBoxPosition : function()
28330 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28331 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28333 this.thumbEl.setLeft(x);
28334 this.thumbEl.setTop(y);
28338 baseRotateLevel : function()
28340 this.baseRotate = 1;
28343 typeof(this.exif) != 'undefined' &&
28344 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28345 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28347 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28350 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28354 baseScaleLevel : function()
28358 if(this.isDocument){
28360 if(this.baseRotate == 6 || this.baseRotate == 8){
28362 height = this.thumbEl.getHeight();
28363 this.baseScale = height / this.imageEl.OriginWidth;
28365 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28366 width = this.thumbEl.getWidth();
28367 this.baseScale = width / this.imageEl.OriginHeight;
28373 height = this.thumbEl.getHeight();
28374 this.baseScale = height / this.imageEl.OriginHeight;
28376 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28377 width = this.thumbEl.getWidth();
28378 this.baseScale = width / this.imageEl.OriginWidth;
28384 if(this.baseRotate == 6 || this.baseRotate == 8){
28386 width = this.thumbEl.getHeight();
28387 this.baseScale = width / this.imageEl.OriginHeight;
28389 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28390 height = this.thumbEl.getWidth();
28391 this.baseScale = height / this.imageEl.OriginHeight;
28394 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28395 height = this.thumbEl.getWidth();
28396 this.baseScale = height / this.imageEl.OriginHeight;
28398 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28399 width = this.thumbEl.getHeight();
28400 this.baseScale = width / this.imageEl.OriginWidth;
28407 width = this.thumbEl.getWidth();
28408 this.baseScale = width / this.imageEl.OriginWidth;
28410 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28411 height = this.thumbEl.getHeight();
28412 this.baseScale = height / this.imageEl.OriginHeight;
28415 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28417 height = this.thumbEl.getHeight();
28418 this.baseScale = height / this.imageEl.OriginHeight;
28420 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28421 width = this.thumbEl.getWidth();
28422 this.baseScale = width / this.imageEl.OriginWidth;
28430 getScaleLevel : function()
28432 return this.baseScale * Math.pow(1.1, this.scale);
28435 onTouchStart : function(e)
28437 if(!this.canvasLoaded){
28438 this.beforeSelectFile(e);
28442 var touches = e.browserEvent.touches;
28448 if(touches.length == 1){
28449 this.onMouseDown(e);
28453 if(touches.length != 2){
28459 for(var i = 0, finger; finger = touches[i]; i++){
28460 coords.push(finger.pageX, finger.pageY);
28463 var x = Math.pow(coords[0] - coords[2], 2);
28464 var y = Math.pow(coords[1] - coords[3], 2);
28466 this.startDistance = Math.sqrt(x + y);
28468 this.startScale = this.scale;
28470 this.pinching = true;
28471 this.dragable = false;
28475 onTouchMove : function(e)
28477 if(!this.pinching && !this.dragable){
28481 var touches = e.browserEvent.touches;
28488 this.onMouseMove(e);
28494 for(var i = 0, finger; finger = touches[i]; i++){
28495 coords.push(finger.pageX, finger.pageY);
28498 var x = Math.pow(coords[0] - coords[2], 2);
28499 var y = Math.pow(coords[1] - coords[3], 2);
28501 this.endDistance = Math.sqrt(x + y);
28503 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28505 if(!this.zoomable()){
28506 this.scale = this.startScale;
28514 onTouchEnd : function(e)
28516 this.pinching = false;
28517 this.dragable = false;
28521 process : function(file, crop)
28524 this.maskEl.mask(this.loadingText);
28527 this.xhr = new XMLHttpRequest();
28529 file.xhr = this.xhr;
28531 this.xhr.open(this.method, this.url, true);
28534 "Accept": "application/json",
28535 "Cache-Control": "no-cache",
28536 "X-Requested-With": "XMLHttpRequest"
28539 for (var headerName in headers) {
28540 var headerValue = headers[headerName];
28542 this.xhr.setRequestHeader(headerName, headerValue);
28548 this.xhr.onload = function()
28550 _this.xhrOnLoad(_this.xhr);
28553 this.xhr.onerror = function()
28555 _this.xhrOnError(_this.xhr);
28558 var formData = new FormData();
28560 formData.append('returnHTML', 'NO');
28563 formData.append('crop', crop);
28566 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28567 formData.append(this.paramName, file, file.name);
28570 if(typeof(file.filename) != 'undefined'){
28571 formData.append('filename', file.filename);
28574 if(typeof(file.mimetype) != 'undefined'){
28575 formData.append('mimetype', file.mimetype);
28578 if(this.fireEvent('arrange', this, formData) != false){
28579 this.xhr.send(formData);
28583 xhrOnLoad : function(xhr)
28586 this.maskEl.unmask();
28589 if (xhr.readyState !== 4) {
28590 this.fireEvent('exception', this, xhr);
28594 var response = Roo.decode(xhr.responseText);
28596 if(!response.success){
28597 this.fireEvent('exception', this, xhr);
28601 var response = Roo.decode(xhr.responseText);
28603 this.fireEvent('upload', this, response);
28607 xhrOnError : function()
28610 this.maskEl.unmask();
28613 Roo.log('xhr on error');
28615 var response = Roo.decode(xhr.responseText);
28621 prepare : function(file)
28624 this.maskEl.mask(this.loadingText);
28630 if(typeof(file) === 'string'){
28631 this.loadCanvas(file);
28635 if(!file || !this.urlAPI){
28640 this.cropType = file.type;
28644 if(this.fireEvent('prepare', this, this.file) != false){
28646 var reader = new FileReader();
28648 reader.onload = function (e) {
28649 if (e.target.error) {
28650 Roo.log(e.target.error);
28654 var buffer = e.target.result,
28655 dataView = new DataView(buffer),
28657 maxOffset = dataView.byteLength - 4,
28661 if (dataView.getUint16(0) === 0xffd8) {
28662 while (offset < maxOffset) {
28663 markerBytes = dataView.getUint16(offset);
28665 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28666 markerLength = dataView.getUint16(offset + 2) + 2;
28667 if (offset + markerLength > dataView.byteLength) {
28668 Roo.log('Invalid meta data: Invalid segment size.');
28672 if(markerBytes == 0xffe1){
28673 _this.parseExifData(
28680 offset += markerLength;
28690 var url = _this.urlAPI.createObjectURL(_this.file);
28692 _this.loadCanvas(url);
28697 reader.readAsArrayBuffer(this.file);
28703 parseExifData : function(dataView, offset, length)
28705 var tiffOffset = offset + 10,
28709 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28710 // No Exif data, might be XMP data instead
28714 // Check for the ASCII code for "Exif" (0x45786966):
28715 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28716 // No Exif data, might be XMP data instead
28719 if (tiffOffset + 8 > dataView.byteLength) {
28720 Roo.log('Invalid Exif data: Invalid segment size.');
28723 // Check for the two null bytes:
28724 if (dataView.getUint16(offset + 8) !== 0x0000) {
28725 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28728 // Check the byte alignment:
28729 switch (dataView.getUint16(tiffOffset)) {
28731 littleEndian = true;
28734 littleEndian = false;
28737 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28740 // Check for the TIFF tag marker (0x002A):
28741 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28742 Roo.log('Invalid Exif data: Missing TIFF marker.');
28745 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28746 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28748 this.parseExifTags(
28751 tiffOffset + dirOffset,
28756 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28761 if (dirOffset + 6 > dataView.byteLength) {
28762 Roo.log('Invalid Exif data: Invalid directory offset.');
28765 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28766 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28767 if (dirEndOffset + 4 > dataView.byteLength) {
28768 Roo.log('Invalid Exif data: Invalid directory size.');
28771 for (i = 0; i < tagsNumber; i += 1) {
28775 dirOffset + 2 + 12 * i, // tag offset
28779 // Return the offset to the next directory:
28780 return dataView.getUint32(dirEndOffset, littleEndian);
28783 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28785 var tag = dataView.getUint16(offset, littleEndian);
28787 this.exif[tag] = this.getExifValue(
28791 dataView.getUint16(offset + 2, littleEndian), // tag type
28792 dataView.getUint32(offset + 4, littleEndian), // tag length
28797 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28799 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28808 Roo.log('Invalid Exif data: Invalid tag type.');
28812 tagSize = tagType.size * length;
28813 // Determine if the value is contained in the dataOffset bytes,
28814 // or if the value at the dataOffset is a pointer to the actual data:
28815 dataOffset = tagSize > 4 ?
28816 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28817 if (dataOffset + tagSize > dataView.byteLength) {
28818 Roo.log('Invalid Exif data: Invalid data offset.');
28821 if (length === 1) {
28822 return tagType.getValue(dataView, dataOffset, littleEndian);
28825 for (i = 0; i < length; i += 1) {
28826 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28829 if (tagType.ascii) {
28831 // Concatenate the chars:
28832 for (i = 0; i < values.length; i += 1) {
28834 // Ignore the terminating NULL byte(s):
28835 if (c === '\u0000') {
28847 Roo.apply(Roo.bootstrap.UploadCropbox, {
28849 'Orientation': 0x0112
28853 1: 0, //'top-left',
28855 3: 180, //'bottom-right',
28856 // 4: 'bottom-left',
28858 6: 90, //'right-top',
28859 // 7: 'right-bottom',
28860 8: 270 //'left-bottom'
28864 // byte, 8-bit unsigned int:
28866 getValue: function (dataView, dataOffset) {
28867 return dataView.getUint8(dataOffset);
28871 // ascii, 8-bit byte:
28873 getValue: function (dataView, dataOffset) {
28874 return String.fromCharCode(dataView.getUint8(dataOffset));
28879 // short, 16 bit int:
28881 getValue: function (dataView, dataOffset, littleEndian) {
28882 return dataView.getUint16(dataOffset, littleEndian);
28886 // long, 32 bit int:
28888 getValue: function (dataView, dataOffset, littleEndian) {
28889 return dataView.getUint32(dataOffset, littleEndian);
28893 // rational = two long values, first is numerator, second is denominator:
28895 getValue: function (dataView, dataOffset, littleEndian) {
28896 return dataView.getUint32(dataOffset, littleEndian) /
28897 dataView.getUint32(dataOffset + 4, littleEndian);
28901 // slong, 32 bit signed int:
28903 getValue: function (dataView, dataOffset, littleEndian) {
28904 return dataView.getInt32(dataOffset, littleEndian);
28908 // srational, two slongs, first is numerator, second is denominator:
28910 getValue: function (dataView, dataOffset, littleEndian) {
28911 return dataView.getInt32(dataOffset, littleEndian) /
28912 dataView.getInt32(dataOffset + 4, littleEndian);
28922 cls : 'btn-group roo-upload-cropbox-rotate-left',
28923 action : 'rotate-left',
28927 cls : 'btn btn-default',
28928 html : '<i class="fa fa-undo"></i>'
28934 cls : 'btn-group roo-upload-cropbox-picture',
28935 action : 'picture',
28939 cls : 'btn btn-default',
28940 html : '<i class="fa fa-picture-o"></i>'
28946 cls : 'btn-group roo-upload-cropbox-rotate-right',
28947 action : 'rotate-right',
28951 cls : 'btn btn-default',
28952 html : '<i class="fa fa-repeat"></i>'
28960 cls : 'btn-group roo-upload-cropbox-rotate-left',
28961 action : 'rotate-left',
28965 cls : 'btn btn-default',
28966 html : '<i class="fa fa-undo"></i>'
28972 cls : 'btn-group roo-upload-cropbox-download',
28973 action : 'download',
28977 cls : 'btn btn-default',
28978 html : '<i class="fa fa-download"></i>'
28984 cls : 'btn-group roo-upload-cropbox-crop',
28989 cls : 'btn btn-default',
28990 html : '<i class="fa fa-crop"></i>'
28996 cls : 'btn-group roo-upload-cropbox-trash',
29001 cls : 'btn btn-default',
29002 html : '<i class="fa fa-trash"></i>'
29008 cls : 'btn-group roo-upload-cropbox-rotate-right',
29009 action : 'rotate-right',
29013 cls : 'btn btn-default',
29014 html : '<i class="fa fa-repeat"></i>'
29022 cls : 'btn-group roo-upload-cropbox-rotate-left',
29023 action : 'rotate-left',
29027 cls : 'btn btn-default',
29028 html : '<i class="fa fa-undo"></i>'
29034 cls : 'btn-group roo-upload-cropbox-rotate-right',
29035 action : 'rotate-right',
29039 cls : 'btn btn-default',
29040 html : '<i class="fa fa-repeat"></i>'
29053 * @class Roo.bootstrap.DocumentManager
29054 * @extends Roo.bootstrap.Component
29055 * Bootstrap DocumentManager class
29056 * @cfg {String} paramName default 'imageUpload'
29057 * @cfg {String} toolTipName default 'filename'
29058 * @cfg {String} method default POST
29059 * @cfg {String} url action url
29060 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29061 * @cfg {Boolean} multiple multiple upload default true
29062 * @cfg {Number} thumbSize default 300
29063 * @cfg {String} fieldLabel
29064 * @cfg {Number} labelWidth default 4
29065 * @cfg {String} labelAlign (left|top) default left
29066 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29067 * @cfg {Number} labellg set the width of label (1-12)
29068 * @cfg {Number} labelmd set the width of label (1-12)
29069 * @cfg {Number} labelsm set the width of label (1-12)
29070 * @cfg {Number} labelxs set the width of label (1-12)
29073 * Create a new DocumentManager
29074 * @param {Object} config The config object
29077 Roo.bootstrap.DocumentManager = function(config){
29078 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29081 this.delegates = [];
29086 * Fire when initial the DocumentManager
29087 * @param {Roo.bootstrap.DocumentManager} this
29092 * inspect selected file
29093 * @param {Roo.bootstrap.DocumentManager} this
29094 * @param {File} file
29099 * Fire when xhr load exception
29100 * @param {Roo.bootstrap.DocumentManager} this
29101 * @param {XMLHttpRequest} xhr
29103 "exception" : true,
29105 * @event afterupload
29106 * Fire when xhr load exception
29107 * @param {Roo.bootstrap.DocumentManager} this
29108 * @param {XMLHttpRequest} xhr
29110 "afterupload" : true,
29113 * prepare the form data
29114 * @param {Roo.bootstrap.DocumentManager} this
29115 * @param {Object} formData
29120 * Fire when remove the file
29121 * @param {Roo.bootstrap.DocumentManager} this
29122 * @param {Object} file
29127 * Fire after refresh the file
29128 * @param {Roo.bootstrap.DocumentManager} this
29133 * Fire after click the image
29134 * @param {Roo.bootstrap.DocumentManager} this
29135 * @param {Object} file
29140 * Fire when upload a image and editable set to true
29141 * @param {Roo.bootstrap.DocumentManager} this
29142 * @param {Object} file
29146 * @event beforeselectfile
29147 * Fire before select file
29148 * @param {Roo.bootstrap.DocumentManager} this
29150 "beforeselectfile" : true,
29153 * Fire before process file
29154 * @param {Roo.bootstrap.DocumentManager} this
29155 * @param {Object} file
29159 * @event previewrendered
29160 * Fire when preview rendered
29161 * @param {Roo.bootstrap.DocumentManager} this
29162 * @param {Object} file
29164 "previewrendered" : true,
29167 "previewResize" : true
29172 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29181 paramName : 'imageUpload',
29182 toolTipName : 'filename',
29185 labelAlign : 'left',
29195 getAutoCreate : function()
29197 var managerWidget = {
29199 cls : 'roo-document-manager',
29203 cls : 'roo-document-manager-selector',
29208 cls : 'roo-document-manager-uploader',
29212 cls : 'roo-document-manager-upload-btn',
29213 html : '<i class="fa fa-plus"></i>'
29224 cls : 'column col-md-12',
29229 if(this.fieldLabel.length){
29234 cls : 'column col-md-12',
29235 html : this.fieldLabel
29239 cls : 'column col-md-12',
29244 if(this.labelAlign == 'left'){
29249 html : this.fieldLabel
29258 if(this.labelWidth > 12){
29259 content[0].style = "width: " + this.labelWidth + 'px';
29262 if(this.labelWidth < 13 && this.labelmd == 0){
29263 this.labelmd = this.labelWidth;
29266 if(this.labellg > 0){
29267 content[0].cls += ' col-lg-' + this.labellg;
29268 content[1].cls += ' col-lg-' + (12 - this.labellg);
29271 if(this.labelmd > 0){
29272 content[0].cls += ' col-md-' + this.labelmd;
29273 content[1].cls += ' col-md-' + (12 - this.labelmd);
29276 if(this.labelsm > 0){
29277 content[0].cls += ' col-sm-' + this.labelsm;
29278 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29281 if(this.labelxs > 0){
29282 content[0].cls += ' col-xs-' + this.labelxs;
29283 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29291 cls : 'row clearfix',
29299 initEvents : function()
29301 this.managerEl = this.el.select('.roo-document-manager', true).first();
29302 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29304 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29305 this.selectorEl.hide();
29308 this.selectorEl.attr('multiple', 'multiple');
29311 this.selectorEl.on('change', this.onFileSelected, this);
29313 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29314 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29316 this.uploader.on('click', this.onUploaderClick, this);
29318 this.renderProgressDialog();
29322 window.addEventListener("resize", function() { _this.refresh(); } );
29324 this.fireEvent('initial', this);
29327 renderProgressDialog : function()
29331 this.progressDialog = new Roo.bootstrap.Modal({
29332 cls : 'roo-document-manager-progress-dialog',
29333 allow_close : false,
29344 btnclick : function() {
29345 _this.uploadCancel();
29351 this.progressDialog.render(Roo.get(document.body));
29353 this.progress = new Roo.bootstrap.Progress({
29354 cls : 'roo-document-manager-progress',
29359 this.progress.render(this.progressDialog.getChildContainer());
29361 this.progressBar = new Roo.bootstrap.ProgressBar({
29362 cls : 'roo-document-manager-progress-bar',
29365 aria_valuemax : 12,
29369 this.progressBar.render(this.progress.getChildContainer());
29372 onUploaderClick : function(e)
29374 e.preventDefault();
29376 if(this.fireEvent('beforeselectfile', this) != false){
29377 this.selectorEl.dom.click();
29382 onFileSelected : function(e)
29384 e.preventDefault();
29386 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29390 Roo.each(this.selectorEl.dom.files, function(file){
29391 if(this.fireEvent('inspect', this, file) != false){
29392 this.files.push(file);
29402 this.selectorEl.dom.value = '';
29404 if(!this.files || !this.files.length){
29408 if(this.boxes > 0 && this.files.length > this.boxes){
29409 this.files = this.files.slice(0, this.boxes);
29412 this.uploader.show();
29414 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29415 this.uploader.hide();
29424 Roo.each(this.files, function(file){
29426 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29427 var f = this.renderPreview(file);
29432 if(file.type.indexOf('image') != -1){
29433 this.delegates.push(
29435 _this.process(file);
29436 }).createDelegate(this)
29444 _this.process(file);
29445 }).createDelegate(this)
29450 this.files = files;
29452 this.delegates = this.delegates.concat(docs);
29454 if(!this.delegates.length){
29459 this.progressBar.aria_valuemax = this.delegates.length;
29466 arrange : function()
29468 if(!this.delegates.length){
29469 this.progressDialog.hide();
29474 var delegate = this.delegates.shift();
29476 this.progressDialog.show();
29478 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29480 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29485 refresh : function()
29487 this.uploader.show();
29489 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29490 this.uploader.hide();
29493 Roo.isTouch ? this.closable(false) : this.closable(true);
29495 this.fireEvent('refresh', this);
29498 onRemove : function(e, el, o)
29500 e.preventDefault();
29502 this.fireEvent('remove', this, o);
29506 remove : function(o)
29510 Roo.each(this.files, function(file){
29511 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29520 this.files = files;
29527 Roo.each(this.files, function(file){
29532 file.target.remove();
29541 onClick : function(e, el, o)
29543 e.preventDefault();
29545 this.fireEvent('click', this, o);
29549 closable : function(closable)
29551 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29553 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29565 xhrOnLoad : function(xhr)
29567 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29571 if (xhr.readyState !== 4) {
29573 this.fireEvent('exception', this, xhr);
29577 var response = Roo.decode(xhr.responseText);
29579 if(!response.success){
29581 this.fireEvent('exception', this, xhr);
29585 var file = this.renderPreview(response.data);
29587 this.files.push(file);
29591 this.fireEvent('afterupload', this, xhr);
29595 xhrOnError : function(xhr)
29597 Roo.log('xhr on error');
29599 var response = Roo.decode(xhr.responseText);
29606 process : function(file)
29608 if(this.fireEvent('process', this, file) !== false){
29609 if(this.editable && file.type.indexOf('image') != -1){
29610 this.fireEvent('edit', this, file);
29614 this.uploadStart(file, false);
29621 uploadStart : function(file, crop)
29623 this.xhr = new XMLHttpRequest();
29625 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29630 file.xhr = this.xhr;
29632 this.managerEl.createChild({
29634 cls : 'roo-document-manager-loading',
29638 tooltip : file.name,
29639 cls : 'roo-document-manager-thumb',
29640 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29646 this.xhr.open(this.method, this.url, true);
29649 "Accept": "application/json",
29650 "Cache-Control": "no-cache",
29651 "X-Requested-With": "XMLHttpRequest"
29654 for (var headerName in headers) {
29655 var headerValue = headers[headerName];
29657 this.xhr.setRequestHeader(headerName, headerValue);
29663 this.xhr.onload = function()
29665 _this.xhrOnLoad(_this.xhr);
29668 this.xhr.onerror = function()
29670 _this.xhrOnError(_this.xhr);
29673 var formData = new FormData();
29675 formData.append('returnHTML', 'NO');
29678 formData.append('crop', crop);
29681 formData.append(this.paramName, file, file.name);
29688 if(this.fireEvent('prepare', this, formData, options) != false){
29690 if(options.manually){
29694 this.xhr.send(formData);
29698 this.uploadCancel();
29701 uploadCancel : function()
29707 this.delegates = [];
29709 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29716 renderPreview : function(file)
29718 if(typeof(file.target) != 'undefined' && file.target){
29722 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29724 var previewEl = this.managerEl.createChild({
29726 cls : 'roo-document-manager-preview',
29730 tooltip : file[this.toolTipName],
29731 cls : 'roo-document-manager-thumb',
29732 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29737 html : '<i class="fa fa-times-circle"></i>'
29742 var close = previewEl.select('button.close', true).first();
29744 close.on('click', this.onRemove, this, file);
29746 file.target = previewEl;
29748 var image = previewEl.select('img', true).first();
29752 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29754 image.on('click', this.onClick, this, file);
29756 this.fireEvent('previewrendered', this, file);
29762 onPreviewLoad : function(file, image)
29764 if(typeof(file.target) == 'undefined' || !file.target){
29768 var width = image.dom.naturalWidth || image.dom.width;
29769 var height = image.dom.naturalHeight || image.dom.height;
29771 if(!this.previewResize) {
29775 if(width > height){
29776 file.target.addClass('wide');
29780 file.target.addClass('tall');
29785 uploadFromSource : function(file, crop)
29787 this.xhr = new XMLHttpRequest();
29789 this.managerEl.createChild({
29791 cls : 'roo-document-manager-loading',
29795 tooltip : file.name,
29796 cls : 'roo-document-manager-thumb',
29797 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29803 this.xhr.open(this.method, this.url, true);
29806 "Accept": "application/json",
29807 "Cache-Control": "no-cache",
29808 "X-Requested-With": "XMLHttpRequest"
29811 for (var headerName in headers) {
29812 var headerValue = headers[headerName];
29814 this.xhr.setRequestHeader(headerName, headerValue);
29820 this.xhr.onload = function()
29822 _this.xhrOnLoad(_this.xhr);
29825 this.xhr.onerror = function()
29827 _this.xhrOnError(_this.xhr);
29830 var formData = new FormData();
29832 formData.append('returnHTML', 'NO');
29834 formData.append('crop', crop);
29836 if(typeof(file.filename) != 'undefined'){
29837 formData.append('filename', file.filename);
29840 if(typeof(file.mimetype) != 'undefined'){
29841 formData.append('mimetype', file.mimetype);
29846 if(this.fireEvent('prepare', this, formData) != false){
29847 this.xhr.send(formData);
29857 * @class Roo.bootstrap.DocumentViewer
29858 * @extends Roo.bootstrap.Component
29859 * Bootstrap DocumentViewer class
29860 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29861 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29864 * Create a new DocumentViewer
29865 * @param {Object} config The config object
29868 Roo.bootstrap.DocumentViewer = function(config){
29869 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29874 * Fire after initEvent
29875 * @param {Roo.bootstrap.DocumentViewer} this
29881 * @param {Roo.bootstrap.DocumentViewer} this
29886 * Fire after download button
29887 * @param {Roo.bootstrap.DocumentViewer} this
29892 * Fire after trash button
29893 * @param {Roo.bootstrap.DocumentViewer} this
29900 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29902 showDownload : true,
29906 getAutoCreate : function()
29910 cls : 'roo-document-viewer',
29914 cls : 'roo-document-viewer-body',
29918 cls : 'roo-document-viewer-thumb',
29922 cls : 'roo-document-viewer-image'
29930 cls : 'roo-document-viewer-footer',
29933 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29937 cls : 'btn-group roo-document-viewer-download',
29941 cls : 'btn btn-default',
29942 html : '<i class="fa fa-download"></i>'
29948 cls : 'btn-group roo-document-viewer-trash',
29952 cls : 'btn btn-default',
29953 html : '<i class="fa fa-trash"></i>'
29966 initEvents : function()
29968 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29969 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29971 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29972 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29974 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29975 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29977 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29978 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29980 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29981 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29983 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29984 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29986 this.bodyEl.on('click', this.onClick, this);
29987 this.downloadBtn.on('click', this.onDownload, this);
29988 this.trashBtn.on('click', this.onTrash, this);
29990 this.downloadBtn.hide();
29991 this.trashBtn.hide();
29993 if(this.showDownload){
29994 this.downloadBtn.show();
29997 if(this.showTrash){
29998 this.trashBtn.show();
30001 if(!this.showDownload && !this.showTrash) {
30002 this.footerEl.hide();
30007 initial : function()
30009 this.fireEvent('initial', this);
30013 onClick : function(e)
30015 e.preventDefault();
30017 this.fireEvent('click', this);
30020 onDownload : function(e)
30022 e.preventDefault();
30024 this.fireEvent('download', this);
30027 onTrash : function(e)
30029 e.preventDefault();
30031 this.fireEvent('trash', this);
30043 * @class Roo.bootstrap.NavProgressBar
30044 * @extends Roo.bootstrap.Component
30045 * Bootstrap NavProgressBar class
30048 * Create a new nav progress bar
30049 * @param {Object} config The config object
30052 Roo.bootstrap.NavProgressBar = function(config){
30053 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30055 this.bullets = this.bullets || [];
30057 // Roo.bootstrap.NavProgressBar.register(this);
30061 * Fires when the active item changes
30062 * @param {Roo.bootstrap.NavProgressBar} this
30063 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30064 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30071 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30076 getAutoCreate : function()
30078 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30082 cls : 'roo-navigation-bar-group',
30086 cls : 'roo-navigation-top-bar'
30090 cls : 'roo-navigation-bullets-bar',
30094 cls : 'roo-navigation-bar'
30101 cls : 'roo-navigation-bottom-bar'
30111 initEvents: function()
30116 onRender : function(ct, position)
30118 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30120 if(this.bullets.length){
30121 Roo.each(this.bullets, function(b){
30130 addItem : function(cfg)
30132 var item = new Roo.bootstrap.NavProgressItem(cfg);
30134 item.parentId = this.id;
30135 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30138 var top = new Roo.bootstrap.Element({
30140 cls : 'roo-navigation-bar-text'
30143 var bottom = new Roo.bootstrap.Element({
30145 cls : 'roo-navigation-bar-text'
30148 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30149 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30151 var topText = new Roo.bootstrap.Element({
30153 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30156 var bottomText = new Roo.bootstrap.Element({
30158 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30161 topText.onRender(top.el, null);
30162 bottomText.onRender(bottom.el, null);
30165 item.bottomEl = bottom;
30168 this.barItems.push(item);
30173 getActive : function()
30175 var active = false;
30177 Roo.each(this.barItems, function(v){
30179 if (!v.isActive()) {
30191 setActiveItem : function(item)
30195 Roo.each(this.barItems, function(v){
30196 if (v.rid == item.rid) {
30200 if (v.isActive()) {
30201 v.setActive(false);
30206 item.setActive(true);
30208 this.fireEvent('changed', this, item, prev);
30211 getBarItem: function(rid)
30215 Roo.each(this.barItems, function(e) {
30216 if (e.rid != rid) {
30227 indexOfItem : function(item)
30231 Roo.each(this.barItems, function(v, i){
30233 if (v.rid != item.rid) {
30244 setActiveNext : function()
30246 var i = this.indexOfItem(this.getActive());
30248 if (i > this.barItems.length) {
30252 this.setActiveItem(this.barItems[i+1]);
30255 setActivePrev : function()
30257 var i = this.indexOfItem(this.getActive());
30263 this.setActiveItem(this.barItems[i-1]);
30266 format : function()
30268 if(!this.barItems.length){
30272 var width = 100 / this.barItems.length;
30274 Roo.each(this.barItems, function(i){
30275 i.el.setStyle('width', width + '%');
30276 i.topEl.el.setStyle('width', width + '%');
30277 i.bottomEl.el.setStyle('width', width + '%');
30286 * Nav Progress Item
30291 * @class Roo.bootstrap.NavProgressItem
30292 * @extends Roo.bootstrap.Component
30293 * Bootstrap NavProgressItem class
30294 * @cfg {String} rid the reference id
30295 * @cfg {Boolean} active (true|false) Is item active default false
30296 * @cfg {Boolean} disabled (true|false) Is item active default false
30297 * @cfg {String} html
30298 * @cfg {String} position (top|bottom) text position default bottom
30299 * @cfg {String} icon show icon instead of number
30302 * Create a new NavProgressItem
30303 * @param {Object} config The config object
30305 Roo.bootstrap.NavProgressItem = function(config){
30306 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30311 * The raw click event for the entire grid.
30312 * @param {Roo.bootstrap.NavProgressItem} this
30313 * @param {Roo.EventObject} e
30320 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30326 position : 'bottom',
30329 getAutoCreate : function()
30331 var iconCls = 'roo-navigation-bar-item-icon';
30333 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30337 cls: 'roo-navigation-bar-item',
30347 cfg.cls += ' active';
30350 cfg.cls += ' disabled';
30356 disable : function()
30358 this.setDisabled(true);
30361 enable : function()
30363 this.setDisabled(false);
30366 initEvents: function()
30368 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30370 this.iconEl.on('click', this.onClick, this);
30373 onClick : function(e)
30375 e.preventDefault();
30381 if(this.fireEvent('click', this, e) === false){
30385 this.parent().setActiveItem(this);
30388 isActive: function ()
30390 return this.active;
30393 setActive : function(state)
30395 if(this.active == state){
30399 this.active = state;
30402 this.el.addClass('active');
30406 this.el.removeClass('active');
30411 setDisabled : function(state)
30413 if(this.disabled == state){
30417 this.disabled = state;
30420 this.el.addClass('disabled');
30424 this.el.removeClass('disabled');
30427 tooltipEl : function()
30429 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30442 * @class Roo.bootstrap.FieldLabel
30443 * @extends Roo.bootstrap.Component
30444 * Bootstrap FieldLabel class
30445 * @cfg {String} html contents of the element
30446 * @cfg {String} tag tag of the element default label
30447 * @cfg {String} cls class of the element
30448 * @cfg {String} target label target
30449 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30450 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30451 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30452 * @cfg {String} iconTooltip default "This field is required"
30453 * @cfg {String} indicatorpos (left|right) default left
30456 * Create a new FieldLabel
30457 * @param {Object} config The config object
30460 Roo.bootstrap.FieldLabel = function(config){
30461 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30466 * Fires after the field has been marked as invalid.
30467 * @param {Roo.form.FieldLabel} this
30468 * @param {String} msg The validation message
30473 * Fires after the field has been validated with no errors.
30474 * @param {Roo.form.FieldLabel} this
30480 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30487 invalidClass : 'has-warning',
30488 validClass : 'has-success',
30489 iconTooltip : 'This field is required',
30490 indicatorpos : 'left',
30492 getAutoCreate : function(){
30495 if (!this.allowBlank) {
30501 cls : 'roo-bootstrap-field-label ' + this.cls,
30506 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30507 tooltip : this.iconTooltip
30516 if(this.indicatorpos == 'right'){
30519 cls : 'roo-bootstrap-field-label ' + this.cls,
30528 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30529 tooltip : this.iconTooltip
30538 initEvents: function()
30540 Roo.bootstrap.Element.superclass.initEvents.call(this);
30542 this.indicator = this.indicatorEl();
30544 if(this.indicator){
30545 this.indicator.removeClass('visible');
30546 this.indicator.addClass('invisible');
30549 Roo.bootstrap.FieldLabel.register(this);
30552 indicatorEl : function()
30554 var indicator = this.el.select('i.roo-required-indicator',true).first();
30565 * Mark this field as valid
30567 markValid : function()
30569 if(this.indicator){
30570 this.indicator.removeClass('visible');
30571 this.indicator.addClass('invisible');
30573 if (Roo.bootstrap.version == 3) {
30574 this.el.removeClass(this.invalidClass);
30575 this.el.addClass(this.validClass);
30577 this.el.removeClass('is-invalid');
30578 this.el.addClass('is-valid');
30582 this.fireEvent('valid', this);
30586 * Mark this field as invalid
30587 * @param {String} msg The validation message
30589 markInvalid : function(msg)
30591 if(this.indicator){
30592 this.indicator.removeClass('invisible');
30593 this.indicator.addClass('visible');
30595 if (Roo.bootstrap.version == 3) {
30596 this.el.removeClass(this.validClass);
30597 this.el.addClass(this.invalidClass);
30599 this.el.removeClass('is-valid');
30600 this.el.addClass('is-invalid');
30604 this.fireEvent('invalid', this, msg);
30610 Roo.apply(Roo.bootstrap.FieldLabel, {
30615 * register a FieldLabel Group
30616 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30618 register : function(label)
30620 if(this.groups.hasOwnProperty(label.target)){
30624 this.groups[label.target] = label;
30628 * fetch a FieldLabel Group based on the target
30629 * @param {string} target
30630 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30632 get: function(target) {
30633 if (typeof(this.groups[target]) == 'undefined') {
30637 return this.groups[target] ;
30646 * page DateSplitField.
30652 * @class Roo.bootstrap.DateSplitField
30653 * @extends Roo.bootstrap.Component
30654 * Bootstrap DateSplitField class
30655 * @cfg {string} fieldLabel - the label associated
30656 * @cfg {Number} labelWidth set the width of label (0-12)
30657 * @cfg {String} labelAlign (top|left)
30658 * @cfg {Boolean} dayAllowBlank (true|false) default false
30659 * @cfg {Boolean} monthAllowBlank (true|false) default false
30660 * @cfg {Boolean} yearAllowBlank (true|false) default false
30661 * @cfg {string} dayPlaceholder
30662 * @cfg {string} monthPlaceholder
30663 * @cfg {string} yearPlaceholder
30664 * @cfg {string} dayFormat default 'd'
30665 * @cfg {string} monthFormat default 'm'
30666 * @cfg {string} yearFormat default 'Y'
30667 * @cfg {Number} labellg set the width of label (1-12)
30668 * @cfg {Number} labelmd set the width of label (1-12)
30669 * @cfg {Number} labelsm set the width of label (1-12)
30670 * @cfg {Number} labelxs set the width of label (1-12)
30674 * Create a new DateSplitField
30675 * @param {Object} config The config object
30678 Roo.bootstrap.DateSplitField = function(config){
30679 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30685 * getting the data of years
30686 * @param {Roo.bootstrap.DateSplitField} this
30687 * @param {Object} years
30692 * getting the data of days
30693 * @param {Roo.bootstrap.DateSplitField} this
30694 * @param {Object} days
30699 * Fires after the field has been marked as invalid.
30700 * @param {Roo.form.Field} this
30701 * @param {String} msg The validation message
30706 * Fires after the field has been validated with no errors.
30707 * @param {Roo.form.Field} this
30713 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30716 labelAlign : 'top',
30718 dayAllowBlank : false,
30719 monthAllowBlank : false,
30720 yearAllowBlank : false,
30721 dayPlaceholder : '',
30722 monthPlaceholder : '',
30723 yearPlaceholder : '',
30727 isFormField : true,
30733 getAutoCreate : function()
30737 cls : 'row roo-date-split-field-group',
30742 cls : 'form-hidden-field roo-date-split-field-group-value',
30748 var labelCls = 'col-md-12';
30749 var contentCls = 'col-md-4';
30751 if(this.fieldLabel){
30755 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30759 html : this.fieldLabel
30764 if(this.labelAlign == 'left'){
30766 if(this.labelWidth > 12){
30767 label.style = "width: " + this.labelWidth + 'px';
30770 if(this.labelWidth < 13 && this.labelmd == 0){
30771 this.labelmd = this.labelWidth;
30774 if(this.labellg > 0){
30775 labelCls = ' col-lg-' + this.labellg;
30776 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30779 if(this.labelmd > 0){
30780 labelCls = ' col-md-' + this.labelmd;
30781 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30784 if(this.labelsm > 0){
30785 labelCls = ' col-sm-' + this.labelsm;
30786 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30789 if(this.labelxs > 0){
30790 labelCls = ' col-xs-' + this.labelxs;
30791 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30795 label.cls += ' ' + labelCls;
30797 cfg.cn.push(label);
30800 Roo.each(['day', 'month', 'year'], function(t){
30803 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30810 inputEl: function ()
30812 return this.el.select('.roo-date-split-field-group-value', true).first();
30815 onRender : function(ct, position)
30819 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30821 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30823 this.dayField = new Roo.bootstrap.ComboBox({
30824 allowBlank : this.dayAllowBlank,
30825 alwaysQuery : true,
30826 displayField : 'value',
30829 forceSelection : true,
30831 placeholder : this.dayPlaceholder,
30832 selectOnFocus : true,
30833 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30834 triggerAction : 'all',
30836 valueField : 'value',
30837 store : new Roo.data.SimpleStore({
30838 data : (function() {
30840 _this.fireEvent('days', _this, days);
30843 fields : [ 'value' ]
30846 select : function (_self, record, index)
30848 _this.setValue(_this.getValue());
30853 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30855 this.monthField = new Roo.bootstrap.MonthField({
30856 after : '<i class=\"fa fa-calendar\"></i>',
30857 allowBlank : this.monthAllowBlank,
30858 placeholder : this.monthPlaceholder,
30861 render : function (_self)
30863 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30864 e.preventDefault();
30868 select : function (_self, oldvalue, newvalue)
30870 _this.setValue(_this.getValue());
30875 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30877 this.yearField = new Roo.bootstrap.ComboBox({
30878 allowBlank : this.yearAllowBlank,
30879 alwaysQuery : true,
30880 displayField : 'value',
30883 forceSelection : true,
30885 placeholder : this.yearPlaceholder,
30886 selectOnFocus : true,
30887 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30888 triggerAction : 'all',
30890 valueField : 'value',
30891 store : new Roo.data.SimpleStore({
30892 data : (function() {
30894 _this.fireEvent('years', _this, years);
30897 fields : [ 'value' ]
30900 select : function (_self, record, index)
30902 _this.setValue(_this.getValue());
30907 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30910 setValue : function(v, format)
30912 this.inputEl.dom.value = v;
30914 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30916 var d = Date.parseDate(v, f);
30923 this.setDay(d.format(this.dayFormat));
30924 this.setMonth(d.format(this.monthFormat));
30925 this.setYear(d.format(this.yearFormat));
30932 setDay : function(v)
30934 this.dayField.setValue(v);
30935 this.inputEl.dom.value = this.getValue();
30940 setMonth : function(v)
30942 this.monthField.setValue(v, true);
30943 this.inputEl.dom.value = this.getValue();
30948 setYear : function(v)
30950 this.yearField.setValue(v);
30951 this.inputEl.dom.value = this.getValue();
30956 getDay : function()
30958 return this.dayField.getValue();
30961 getMonth : function()
30963 return this.monthField.getValue();
30966 getYear : function()
30968 return this.yearField.getValue();
30971 getValue : function()
30973 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30975 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30985 this.inputEl.dom.value = '';
30990 validate : function()
30992 var d = this.dayField.validate();
30993 var m = this.monthField.validate();
30994 var y = this.yearField.validate();
30999 (!this.dayAllowBlank && !d) ||
31000 (!this.monthAllowBlank && !m) ||
31001 (!this.yearAllowBlank && !y)
31006 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31015 this.markInvalid();
31020 markValid : function()
31023 var label = this.el.select('label', true).first();
31024 var icon = this.el.select('i.fa-star', true).first();
31030 this.fireEvent('valid', this);
31034 * Mark this field as invalid
31035 * @param {String} msg The validation message
31037 markInvalid : function(msg)
31040 var label = this.el.select('label', true).first();
31041 var icon = this.el.select('i.fa-star', true).first();
31043 if(label && !icon){
31044 this.el.select('.roo-date-split-field-label', true).createChild({
31046 cls : 'text-danger fa fa-lg fa-star',
31047 tooltip : 'This field is required',
31048 style : 'margin-right:5px;'
31052 this.fireEvent('invalid', this, msg);
31055 clearInvalid : function()
31057 var label = this.el.select('label', true).first();
31058 var icon = this.el.select('i.fa-star', true).first();
31064 this.fireEvent('valid', this);
31067 getName: function()
31077 * http://masonry.desandro.com
31079 * The idea is to render all the bricks based on vertical width...
31081 * The original code extends 'outlayer' - we might need to use that....
31087 * @class Roo.bootstrap.LayoutMasonry
31088 * @extends Roo.bootstrap.Component
31089 * Bootstrap Layout Masonry class
31092 * Create a new Element
31093 * @param {Object} config The config object
31096 Roo.bootstrap.LayoutMasonry = function(config){
31098 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31102 Roo.bootstrap.LayoutMasonry.register(this);
31108 * Fire after layout the items
31109 * @param {Roo.bootstrap.LayoutMasonry} this
31110 * @param {Roo.EventObject} e
31117 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31120 * @cfg {Boolean} isLayoutInstant = no animation?
31122 isLayoutInstant : false, // needed?
31125 * @cfg {Number} boxWidth width of the columns
31130 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31135 * @cfg {Number} padWidth padding below box..
31140 * @cfg {Number} gutter gutter width..
31145 * @cfg {Number} maxCols maximum number of columns
31151 * @cfg {Boolean} isAutoInitial defalut true
31153 isAutoInitial : true,
31158 * @cfg {Boolean} isHorizontal defalut false
31160 isHorizontal : false,
31162 currentSize : null,
31168 bricks: null, //CompositeElement
31172 _isLayoutInited : false,
31174 // isAlternative : false, // only use for vertical layout...
31177 * @cfg {Number} alternativePadWidth padding below box..
31179 alternativePadWidth : 50,
31181 selectedBrick : [],
31183 getAutoCreate : function(){
31185 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31189 cls: 'blog-masonary-wrapper ' + this.cls,
31191 cls : 'mas-boxes masonary'
31198 getChildContainer: function( )
31200 if (this.boxesEl) {
31201 return this.boxesEl;
31204 this.boxesEl = this.el.select('.mas-boxes').first();
31206 return this.boxesEl;
31210 initEvents : function()
31214 if(this.isAutoInitial){
31215 Roo.log('hook children rendered');
31216 this.on('childrenrendered', function() {
31217 Roo.log('children rendered');
31223 initial : function()
31225 this.selectedBrick = [];
31227 this.currentSize = this.el.getBox(true);
31229 Roo.EventManager.onWindowResize(this.resize, this);
31231 if(!this.isAutoInitial){
31239 //this.layout.defer(500,this);
31243 resize : function()
31245 var cs = this.el.getBox(true);
31248 this.currentSize.width == cs.width &&
31249 this.currentSize.x == cs.x &&
31250 this.currentSize.height == cs.height &&
31251 this.currentSize.y == cs.y
31253 Roo.log("no change in with or X or Y");
31257 this.currentSize = cs;
31263 layout : function()
31265 this._resetLayout();
31267 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31269 this.layoutItems( isInstant );
31271 this._isLayoutInited = true;
31273 this.fireEvent('layout', this);
31277 _resetLayout : function()
31279 if(this.isHorizontal){
31280 this.horizontalMeasureColumns();
31284 this.verticalMeasureColumns();
31288 verticalMeasureColumns : function()
31290 this.getContainerWidth();
31292 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31293 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31297 var boxWidth = this.boxWidth + this.padWidth;
31299 if(this.containerWidth < this.boxWidth){
31300 boxWidth = this.containerWidth
31303 var containerWidth = this.containerWidth;
31305 var cols = Math.floor(containerWidth / boxWidth);
31307 this.cols = Math.max( cols, 1 );
31309 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31311 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31313 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31315 this.colWidth = boxWidth + avail - this.padWidth;
31317 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31318 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31321 horizontalMeasureColumns : function()
31323 this.getContainerWidth();
31325 var boxWidth = this.boxWidth;
31327 if(this.containerWidth < boxWidth){
31328 boxWidth = this.containerWidth;
31331 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31333 this.el.setHeight(boxWidth);
31337 getContainerWidth : function()
31339 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31342 layoutItems : function( isInstant )
31344 Roo.log(this.bricks);
31346 var items = Roo.apply([], this.bricks);
31348 if(this.isHorizontal){
31349 this._horizontalLayoutItems( items , isInstant );
31353 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31354 // this._verticalAlternativeLayoutItems( items , isInstant );
31358 this._verticalLayoutItems( items , isInstant );
31362 _verticalLayoutItems : function ( items , isInstant)
31364 if ( !items || !items.length ) {
31369 ['xs', 'xs', 'xs', 'tall'],
31370 ['xs', 'xs', 'tall'],
31371 ['xs', 'xs', 'sm'],
31372 ['xs', 'xs', 'xs'],
31378 ['sm', 'xs', 'xs'],
31382 ['tall', 'xs', 'xs', 'xs'],
31383 ['tall', 'xs', 'xs'],
31395 Roo.each(items, function(item, k){
31397 switch (item.size) {
31398 // these layouts take up a full box,
31409 boxes.push([item]);
31432 var filterPattern = function(box, length)
31440 var pattern = box.slice(0, length);
31444 Roo.each(pattern, function(i){
31445 format.push(i.size);
31448 Roo.each(standard, function(s){
31450 if(String(s) != String(format)){
31459 if(!match && length == 1){
31464 filterPattern(box, length - 1);
31468 queue.push(pattern);
31470 box = box.slice(length, box.length);
31472 filterPattern(box, 4);
31478 Roo.each(boxes, function(box, k){
31484 if(box.length == 1){
31489 filterPattern(box, 4);
31493 this._processVerticalLayoutQueue( queue, isInstant );
31497 // _verticalAlternativeLayoutItems : function( items , isInstant )
31499 // if ( !items || !items.length ) {
31503 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31507 _horizontalLayoutItems : function ( items , isInstant)
31509 if ( !items || !items.length || items.length < 3) {
31515 var eItems = items.slice(0, 3);
31517 items = items.slice(3, items.length);
31520 ['xs', 'xs', 'xs', 'wide'],
31521 ['xs', 'xs', 'wide'],
31522 ['xs', 'xs', 'sm'],
31523 ['xs', 'xs', 'xs'],
31529 ['sm', 'xs', 'xs'],
31533 ['wide', 'xs', 'xs', 'xs'],
31534 ['wide', 'xs', 'xs'],
31547 Roo.each(items, function(item, k){
31549 switch (item.size) {
31560 boxes.push([item]);
31584 var filterPattern = function(box, length)
31592 var pattern = box.slice(0, length);
31596 Roo.each(pattern, function(i){
31597 format.push(i.size);
31600 Roo.each(standard, function(s){
31602 if(String(s) != String(format)){
31611 if(!match && length == 1){
31616 filterPattern(box, length - 1);
31620 queue.push(pattern);
31622 box = box.slice(length, box.length);
31624 filterPattern(box, 4);
31630 Roo.each(boxes, function(box, k){
31636 if(box.length == 1){
31641 filterPattern(box, 4);
31648 var pos = this.el.getBox(true);
31652 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31654 var hit_end = false;
31656 Roo.each(queue, function(box){
31660 Roo.each(box, function(b){
31662 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31672 Roo.each(box, function(b){
31674 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31677 mx = Math.max(mx, b.x);
31681 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31685 Roo.each(box, function(b){
31687 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31701 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31704 /** Sets position of item in DOM
31705 * @param {Element} item
31706 * @param {Number} x - horizontal position
31707 * @param {Number} y - vertical position
31708 * @param {Boolean} isInstant - disables transitions
31710 _processVerticalLayoutQueue : function( queue, isInstant )
31712 var pos = this.el.getBox(true);
31717 for (var i = 0; i < this.cols; i++){
31721 Roo.each(queue, function(box, k){
31723 var col = k % this.cols;
31725 Roo.each(box, function(b,kk){
31727 b.el.position('absolute');
31729 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31730 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31732 if(b.size == 'md-left' || b.size == 'md-right'){
31733 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31734 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31737 b.el.setWidth(width);
31738 b.el.setHeight(height);
31740 b.el.select('iframe',true).setSize(width,height);
31744 for (var i = 0; i < this.cols; i++){
31746 if(maxY[i] < maxY[col]){
31751 col = Math.min(col, i);
31755 x = pos.x + col * (this.colWidth + this.padWidth);
31759 var positions = [];
31761 switch (box.length){
31763 positions = this.getVerticalOneBoxColPositions(x, y, box);
31766 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31769 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31772 positions = this.getVerticalFourBoxColPositions(x, y, box);
31778 Roo.each(box, function(b,kk){
31780 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31782 var sz = b.el.getSize();
31784 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31792 for (var i = 0; i < this.cols; i++){
31793 mY = Math.max(mY, maxY[i]);
31796 this.el.setHeight(mY - pos.y);
31800 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31802 // var pos = this.el.getBox(true);
31805 // var maxX = pos.right;
31807 // var maxHeight = 0;
31809 // Roo.each(items, function(item, k){
31813 // item.el.position('absolute');
31815 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31817 // item.el.setWidth(width);
31819 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31821 // item.el.setHeight(height);
31824 // item.el.setXY([x, y], isInstant ? false : true);
31826 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31829 // y = y + height + this.alternativePadWidth;
31831 // maxHeight = maxHeight + height + this.alternativePadWidth;
31835 // this.el.setHeight(maxHeight);
31839 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31841 var pos = this.el.getBox(true);
31846 var maxX = pos.right;
31848 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31850 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31852 Roo.each(queue, function(box, k){
31854 Roo.each(box, function(b, kk){
31856 b.el.position('absolute');
31858 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31859 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31861 if(b.size == 'md-left' || b.size == 'md-right'){
31862 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31863 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31866 b.el.setWidth(width);
31867 b.el.setHeight(height);
31875 var positions = [];
31877 switch (box.length){
31879 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31882 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31885 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31888 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31894 Roo.each(box, function(b,kk){
31896 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31898 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31906 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31908 Roo.each(eItems, function(b,k){
31910 b.size = (k == 0) ? 'sm' : 'xs';
31911 b.x = (k == 0) ? 2 : 1;
31912 b.y = (k == 0) ? 2 : 1;
31914 b.el.position('absolute');
31916 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31918 b.el.setWidth(width);
31920 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31922 b.el.setHeight(height);
31926 var positions = [];
31929 x : maxX - this.unitWidth * 2 - this.gutter,
31934 x : maxX - this.unitWidth,
31935 y : minY + (this.unitWidth + this.gutter) * 2
31939 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31943 Roo.each(eItems, function(b,k){
31945 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31951 getVerticalOneBoxColPositions : function(x, y, box)
31955 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31957 if(box[0].size == 'md-left'){
31961 if(box[0].size == 'md-right'){
31966 x : x + (this.unitWidth + this.gutter) * rand,
31973 getVerticalTwoBoxColPositions : function(x, y, box)
31977 if(box[0].size == 'xs'){
31981 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31985 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31999 x : x + (this.unitWidth + this.gutter) * 2,
32000 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32007 getVerticalThreeBoxColPositions : function(x, y, box)
32011 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32019 x : x + (this.unitWidth + this.gutter) * 1,
32024 x : x + (this.unitWidth + this.gutter) * 2,
32032 if(box[0].size == 'xs' && box[1].size == 'xs'){
32041 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32045 x : x + (this.unitWidth + this.gutter) * 1,
32059 x : x + (this.unitWidth + this.gutter) * 2,
32064 x : x + (this.unitWidth + this.gutter) * 2,
32065 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32072 getVerticalFourBoxColPositions : function(x, y, box)
32076 if(box[0].size == 'xs'){
32085 y : y + (this.unitHeight + this.gutter) * 1
32090 y : y + (this.unitHeight + this.gutter) * 2
32094 x : x + (this.unitWidth + this.gutter) * 1,
32108 x : x + (this.unitWidth + this.gutter) * 2,
32113 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32114 y : y + (this.unitHeight + this.gutter) * 1
32118 x : x + (this.unitWidth + this.gutter) * 2,
32119 y : y + (this.unitWidth + this.gutter) * 2
32126 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32130 if(box[0].size == 'md-left'){
32132 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32139 if(box[0].size == 'md-right'){
32141 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32142 y : minY + (this.unitWidth + this.gutter) * 1
32148 var rand = Math.floor(Math.random() * (4 - box[0].y));
32151 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32152 y : minY + (this.unitWidth + this.gutter) * rand
32159 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32163 if(box[0].size == 'xs'){
32166 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32171 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32172 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32180 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32185 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32186 y : minY + (this.unitWidth + this.gutter) * 2
32193 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32197 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32200 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32205 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32206 y : minY + (this.unitWidth + this.gutter) * 1
32210 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32211 y : minY + (this.unitWidth + this.gutter) * 2
32218 if(box[0].size == 'xs' && box[1].size == 'xs'){
32221 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32226 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32231 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32232 y : minY + (this.unitWidth + this.gutter) * 1
32240 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32245 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32246 y : minY + (this.unitWidth + this.gutter) * 2
32250 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32251 y : minY + (this.unitWidth + this.gutter) * 2
32258 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32262 if(box[0].size == 'xs'){
32265 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32270 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32275 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),
32280 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32281 y : minY + (this.unitWidth + this.gutter) * 1
32289 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32294 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32295 y : minY + (this.unitWidth + this.gutter) * 2
32299 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32300 y : minY + (this.unitWidth + this.gutter) * 2
32304 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),
32305 y : minY + (this.unitWidth + this.gutter) * 2
32313 * remove a Masonry Brick
32314 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32316 removeBrick : function(brick_id)
32322 for (var i = 0; i<this.bricks.length; i++) {
32323 if (this.bricks[i].id == brick_id) {
32324 this.bricks.splice(i,1);
32325 this.el.dom.removeChild(Roo.get(brick_id).dom);
32332 * adds a Masonry Brick
32333 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32335 addBrick : function(cfg)
32337 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32338 //this.register(cn);
32339 cn.parentId = this.id;
32340 cn.render(this.el);
32345 * register a Masonry Brick
32346 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32349 register : function(brick)
32351 this.bricks.push(brick);
32352 brick.masonryId = this.id;
32356 * clear all the Masonry Brick
32358 clearAll : function()
32361 //this.getChildContainer().dom.innerHTML = "";
32362 this.el.dom.innerHTML = '';
32365 getSelected : function()
32367 if (!this.selectedBrick) {
32371 return this.selectedBrick;
32375 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32379 * register a Masonry Layout
32380 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32383 register : function(layout)
32385 this.groups[layout.id] = layout;
32388 * fetch a Masonry Layout based on the masonry layout ID
32389 * @param {string} the masonry layout to add
32390 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32393 get: function(layout_id) {
32394 if (typeof(this.groups[layout_id]) == 'undefined') {
32397 return this.groups[layout_id] ;
32409 * http://masonry.desandro.com
32411 * The idea is to render all the bricks based on vertical width...
32413 * The original code extends 'outlayer' - we might need to use that....
32419 * @class Roo.bootstrap.LayoutMasonryAuto
32420 * @extends Roo.bootstrap.Component
32421 * Bootstrap Layout Masonry class
32424 * Create a new Element
32425 * @param {Object} config The config object
32428 Roo.bootstrap.LayoutMasonryAuto = function(config){
32429 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32432 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32435 * @cfg {Boolean} isFitWidth - resize the width..
32437 isFitWidth : false, // options..
32439 * @cfg {Boolean} isOriginLeft = left align?
32441 isOriginLeft : true,
32443 * @cfg {Boolean} isOriginTop = top align?
32445 isOriginTop : false,
32447 * @cfg {Boolean} isLayoutInstant = no animation?
32449 isLayoutInstant : false, // needed?
32451 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32453 isResizingContainer : true,
32455 * @cfg {Number} columnWidth width of the columns
32461 * @cfg {Number} maxCols maximum number of columns
32466 * @cfg {Number} padHeight padding below box..
32472 * @cfg {Boolean} isAutoInitial defalut true
32475 isAutoInitial : true,
32481 initialColumnWidth : 0,
32482 currentSize : null,
32484 colYs : null, // array.
32491 bricks: null, //CompositeElement
32492 cols : 0, // array?
32493 // element : null, // wrapped now this.el
32494 _isLayoutInited : null,
32497 getAutoCreate : function(){
32501 cls: 'blog-masonary-wrapper ' + this.cls,
32503 cls : 'mas-boxes masonary'
32510 getChildContainer: function( )
32512 if (this.boxesEl) {
32513 return this.boxesEl;
32516 this.boxesEl = this.el.select('.mas-boxes').first();
32518 return this.boxesEl;
32522 initEvents : function()
32526 if(this.isAutoInitial){
32527 Roo.log('hook children rendered');
32528 this.on('childrenrendered', function() {
32529 Roo.log('children rendered');
32536 initial : function()
32538 this.reloadItems();
32540 this.currentSize = this.el.getBox(true);
32542 /// was window resize... - let's see if this works..
32543 Roo.EventManager.onWindowResize(this.resize, this);
32545 if(!this.isAutoInitial){
32550 this.layout.defer(500,this);
32553 reloadItems: function()
32555 this.bricks = this.el.select('.masonry-brick', true);
32557 this.bricks.each(function(b) {
32558 //Roo.log(b.getSize());
32559 if (!b.attr('originalwidth')) {
32560 b.attr('originalwidth', b.getSize().width);
32565 Roo.log(this.bricks.elements.length);
32568 resize : function()
32571 var cs = this.el.getBox(true);
32573 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32574 Roo.log("no change in with or X");
32577 this.currentSize = cs;
32581 layout : function()
32584 this._resetLayout();
32585 //this._manageStamps();
32587 // don't animate first layout
32588 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32589 this.layoutItems( isInstant );
32591 // flag for initalized
32592 this._isLayoutInited = true;
32595 layoutItems : function( isInstant )
32597 //var items = this._getItemsForLayout( this.items );
32598 // original code supports filtering layout items.. we just ignore it..
32600 this._layoutItems( this.bricks , isInstant );
32602 this._postLayout();
32604 _layoutItems : function ( items , isInstant)
32606 //this.fireEvent( 'layout', this, items );
32609 if ( !items || !items.elements.length ) {
32610 // no items, emit event with empty array
32615 items.each(function(item) {
32616 Roo.log("layout item");
32618 // get x/y object from method
32619 var position = this._getItemLayoutPosition( item );
32621 position.item = item;
32622 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32623 queue.push( position );
32626 this._processLayoutQueue( queue );
32628 /** Sets position of item in DOM
32629 * @param {Element} item
32630 * @param {Number} x - horizontal position
32631 * @param {Number} y - vertical position
32632 * @param {Boolean} isInstant - disables transitions
32634 _processLayoutQueue : function( queue )
32636 for ( var i=0, len = queue.length; i < len; i++ ) {
32637 var obj = queue[i];
32638 obj.item.position('absolute');
32639 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32645 * Any logic you want to do after each layout,
32646 * i.e. size the container
32648 _postLayout : function()
32650 this.resizeContainer();
32653 resizeContainer : function()
32655 if ( !this.isResizingContainer ) {
32658 var size = this._getContainerSize();
32660 this.el.setSize(size.width,size.height);
32661 this.boxesEl.setSize(size.width,size.height);
32667 _resetLayout : function()
32669 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32670 this.colWidth = this.el.getWidth();
32671 //this.gutter = this.el.getWidth();
32673 this.measureColumns();
32679 this.colYs.push( 0 );
32685 measureColumns : function()
32687 this.getContainerWidth();
32688 // if columnWidth is 0, default to outerWidth of first item
32689 if ( !this.columnWidth ) {
32690 var firstItem = this.bricks.first();
32691 Roo.log(firstItem);
32692 this.columnWidth = this.containerWidth;
32693 if (firstItem && firstItem.attr('originalwidth') ) {
32694 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32696 // columnWidth fall back to item of first element
32697 Roo.log("set column width?");
32698 this.initialColumnWidth = this.columnWidth ;
32700 // if first elem has no width, default to size of container
32705 if (this.initialColumnWidth) {
32706 this.columnWidth = this.initialColumnWidth;
32711 // column width is fixed at the top - however if container width get's smaller we should
32714 // this bit calcs how man columns..
32716 var columnWidth = this.columnWidth += this.gutter;
32718 // calculate columns
32719 var containerWidth = this.containerWidth + this.gutter;
32721 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32722 // fix rounding errors, typically with gutters
32723 var excess = columnWidth - containerWidth % columnWidth;
32726 // if overshoot is less than a pixel, round up, otherwise floor it
32727 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32728 cols = Math[ mathMethod ]( cols );
32729 this.cols = Math.max( cols, 1 );
32730 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32732 // padding positioning..
32733 var totalColWidth = this.cols * this.columnWidth;
32734 var padavail = this.containerWidth - totalColWidth;
32735 // so for 2 columns - we need 3 'pads'
32737 var padNeeded = (1+this.cols) * this.padWidth;
32739 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32741 this.columnWidth += padExtra
32742 //this.padWidth = Math.floor(padavail / ( this.cols));
32744 // adjust colum width so that padding is fixed??
32746 // we have 3 columns ... total = width * 3
32747 // we have X left over... that should be used by
32749 //if (this.expandC) {
32757 getContainerWidth : function()
32759 /* // container is parent if fit width
32760 var container = this.isFitWidth ? this.element.parentNode : this.element;
32761 // check that this.size and size are there
32762 // IE8 triggers resize on body size change, so they might not be
32764 var size = getSize( container ); //FIXME
32765 this.containerWidth = size && size.innerWidth; //FIXME
32768 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32772 _getItemLayoutPosition : function( item ) // what is item?
32774 // we resize the item to our columnWidth..
32776 item.setWidth(this.columnWidth);
32777 item.autoBoxAdjust = false;
32779 var sz = item.getSize();
32781 // how many columns does this brick span
32782 var remainder = this.containerWidth % this.columnWidth;
32784 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32785 // round if off by 1 pixel, otherwise use ceil
32786 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32787 colSpan = Math.min( colSpan, this.cols );
32789 // normally this should be '1' as we dont' currently allow multi width columns..
32791 var colGroup = this._getColGroup( colSpan );
32792 // get the minimum Y value from the columns
32793 var minimumY = Math.min.apply( Math, colGroup );
32794 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32796 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32798 // position the brick
32800 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32801 y: this.currentSize.y + minimumY + this.padHeight
32805 // apply setHeight to necessary columns
32806 var setHeight = minimumY + sz.height + this.padHeight;
32807 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32809 var setSpan = this.cols + 1 - colGroup.length;
32810 for ( var i = 0; i < setSpan; i++ ) {
32811 this.colYs[ shortColIndex + i ] = setHeight ;
32818 * @param {Number} colSpan - number of columns the element spans
32819 * @returns {Array} colGroup
32821 _getColGroup : function( colSpan )
32823 if ( colSpan < 2 ) {
32824 // if brick spans only one column, use all the column Ys
32829 // how many different places could this brick fit horizontally
32830 var groupCount = this.cols + 1 - colSpan;
32831 // for each group potential horizontal position
32832 for ( var i = 0; i < groupCount; i++ ) {
32833 // make an array of colY values for that one group
32834 var groupColYs = this.colYs.slice( i, i + colSpan );
32835 // and get the max value of the array
32836 colGroup[i] = Math.max.apply( Math, groupColYs );
32841 _manageStamp : function( stamp )
32843 var stampSize = stamp.getSize();
32844 var offset = stamp.getBox();
32845 // get the columns that this stamp affects
32846 var firstX = this.isOriginLeft ? offset.x : offset.right;
32847 var lastX = firstX + stampSize.width;
32848 var firstCol = Math.floor( firstX / this.columnWidth );
32849 firstCol = Math.max( 0, firstCol );
32851 var lastCol = Math.floor( lastX / this.columnWidth );
32852 // lastCol should not go over if multiple of columnWidth #425
32853 lastCol -= lastX % this.columnWidth ? 0 : 1;
32854 lastCol = Math.min( this.cols - 1, lastCol );
32856 // set colYs to bottom of the stamp
32857 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32860 for ( var i = firstCol; i <= lastCol; i++ ) {
32861 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32866 _getContainerSize : function()
32868 this.maxY = Math.max.apply( Math, this.colYs );
32873 if ( this.isFitWidth ) {
32874 size.width = this._getContainerFitWidth();
32880 _getContainerFitWidth : function()
32882 var unusedCols = 0;
32883 // count unused columns
32886 if ( this.colYs[i] !== 0 ) {
32891 // fit container to columns that have been used
32892 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32895 needsResizeLayout : function()
32897 var previousWidth = this.containerWidth;
32898 this.getContainerWidth();
32899 return previousWidth !== this.containerWidth;
32914 * @class Roo.bootstrap.MasonryBrick
32915 * @extends Roo.bootstrap.Component
32916 * Bootstrap MasonryBrick class
32919 * Create a new MasonryBrick
32920 * @param {Object} config The config object
32923 Roo.bootstrap.MasonryBrick = function(config){
32925 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32927 Roo.bootstrap.MasonryBrick.register(this);
32933 * When a MasonryBrick is clcik
32934 * @param {Roo.bootstrap.MasonryBrick} this
32935 * @param {Roo.EventObject} e
32941 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32944 * @cfg {String} title
32948 * @cfg {String} html
32952 * @cfg {String} bgimage
32956 * @cfg {String} videourl
32960 * @cfg {String} cls
32964 * @cfg {String} href
32968 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32973 * @cfg {String} placetitle (center|bottom)
32978 * @cfg {Boolean} isFitContainer defalut true
32980 isFitContainer : true,
32983 * @cfg {Boolean} preventDefault defalut false
32985 preventDefault : false,
32988 * @cfg {Boolean} inverse defalut false
32990 maskInverse : false,
32992 getAutoCreate : function()
32994 if(!this.isFitContainer){
32995 return this.getSplitAutoCreate();
32998 var cls = 'masonry-brick masonry-brick-full';
33000 if(this.href.length){
33001 cls += ' masonry-brick-link';
33004 if(this.bgimage.length){
33005 cls += ' masonry-brick-image';
33008 if(this.maskInverse){
33009 cls += ' mask-inverse';
33012 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33013 cls += ' enable-mask';
33017 cls += ' masonry-' + this.size + '-brick';
33020 if(this.placetitle.length){
33022 switch (this.placetitle) {
33024 cls += ' masonry-center-title';
33027 cls += ' masonry-bottom-title';
33034 if(!this.html.length && !this.bgimage.length){
33035 cls += ' masonry-center-title';
33038 if(!this.html.length && this.bgimage.length){
33039 cls += ' masonry-bottom-title';
33044 cls += ' ' + this.cls;
33048 tag: (this.href.length) ? 'a' : 'div',
33053 cls: 'masonry-brick-mask'
33057 cls: 'masonry-brick-paragraph',
33063 if(this.href.length){
33064 cfg.href = this.href;
33067 var cn = cfg.cn[1].cn;
33069 if(this.title.length){
33072 cls: 'masonry-brick-title',
33077 if(this.html.length){
33080 cls: 'masonry-brick-text',
33085 if (!this.title.length && !this.html.length) {
33086 cfg.cn[1].cls += ' hide';
33089 if(this.bgimage.length){
33092 cls: 'masonry-brick-image-view',
33097 if(this.videourl.length){
33098 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33099 // youtube support only?
33102 cls: 'masonry-brick-image-view',
33105 allowfullscreen : true
33113 getSplitAutoCreate : function()
33115 var cls = 'masonry-brick masonry-brick-split';
33117 if(this.href.length){
33118 cls += ' masonry-brick-link';
33121 if(this.bgimage.length){
33122 cls += ' masonry-brick-image';
33126 cls += ' masonry-' + this.size + '-brick';
33129 switch (this.placetitle) {
33131 cls += ' masonry-center-title';
33134 cls += ' masonry-bottom-title';
33137 if(!this.bgimage.length){
33138 cls += ' masonry-center-title';
33141 if(this.bgimage.length){
33142 cls += ' masonry-bottom-title';
33148 cls += ' ' + this.cls;
33152 tag: (this.href.length) ? 'a' : 'div',
33157 cls: 'masonry-brick-split-head',
33161 cls: 'masonry-brick-paragraph',
33168 cls: 'masonry-brick-split-body',
33174 if(this.href.length){
33175 cfg.href = this.href;
33178 if(this.title.length){
33179 cfg.cn[0].cn[0].cn.push({
33181 cls: 'masonry-brick-title',
33186 if(this.html.length){
33187 cfg.cn[1].cn.push({
33189 cls: 'masonry-brick-text',
33194 if(this.bgimage.length){
33195 cfg.cn[0].cn.push({
33197 cls: 'masonry-brick-image-view',
33202 if(this.videourl.length){
33203 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33204 // youtube support only?
33205 cfg.cn[0].cn.cn.push({
33207 cls: 'masonry-brick-image-view',
33210 allowfullscreen : true
33217 initEvents: function()
33219 switch (this.size) {
33252 this.el.on('touchstart', this.onTouchStart, this);
33253 this.el.on('touchmove', this.onTouchMove, this);
33254 this.el.on('touchend', this.onTouchEnd, this);
33255 this.el.on('contextmenu', this.onContextMenu, this);
33257 this.el.on('mouseenter' ,this.enter, this);
33258 this.el.on('mouseleave', this.leave, this);
33259 this.el.on('click', this.onClick, this);
33262 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33263 this.parent().bricks.push(this);
33268 onClick: function(e, el)
33270 var time = this.endTimer - this.startTimer;
33271 // Roo.log(e.preventDefault());
33274 e.preventDefault();
33279 if(!this.preventDefault){
33283 e.preventDefault();
33285 if (this.activeClass != '') {
33286 this.selectBrick();
33289 this.fireEvent('click', this, e);
33292 enter: function(e, el)
33294 e.preventDefault();
33296 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33300 if(this.bgimage.length && this.html.length){
33301 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33305 leave: function(e, el)
33307 e.preventDefault();
33309 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33313 if(this.bgimage.length && this.html.length){
33314 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33318 onTouchStart: function(e, el)
33320 // e.preventDefault();
33322 this.touchmoved = false;
33324 if(!this.isFitContainer){
33328 if(!this.bgimage.length || !this.html.length){
33332 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33334 this.timer = new Date().getTime();
33338 onTouchMove: function(e, el)
33340 this.touchmoved = true;
33343 onContextMenu : function(e,el)
33345 e.preventDefault();
33346 e.stopPropagation();
33350 onTouchEnd: function(e, el)
33352 // e.preventDefault();
33354 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33361 if(!this.bgimage.length || !this.html.length){
33363 if(this.href.length){
33364 window.location.href = this.href;
33370 if(!this.isFitContainer){
33374 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33376 window.location.href = this.href;
33379 //selection on single brick only
33380 selectBrick : function() {
33382 if (!this.parentId) {
33386 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33387 var index = m.selectedBrick.indexOf(this.id);
33390 m.selectedBrick.splice(index,1);
33391 this.el.removeClass(this.activeClass);
33395 for(var i = 0; i < m.selectedBrick.length; i++) {
33396 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33397 b.el.removeClass(b.activeClass);
33400 m.selectedBrick = [];
33402 m.selectedBrick.push(this.id);
33403 this.el.addClass(this.activeClass);
33407 isSelected : function(){
33408 return this.el.hasClass(this.activeClass);
33413 Roo.apply(Roo.bootstrap.MasonryBrick, {
33416 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33418 * register a Masonry Brick
33419 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33422 register : function(brick)
33424 //this.groups[brick.id] = brick;
33425 this.groups.add(brick.id, brick);
33428 * fetch a masonry brick based on the masonry brick ID
33429 * @param {string} the masonry brick to add
33430 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33433 get: function(brick_id)
33435 // if (typeof(this.groups[brick_id]) == 'undefined') {
33438 // return this.groups[brick_id] ;
33440 if(this.groups.key(brick_id)) {
33441 return this.groups.key(brick_id);
33459 * @class Roo.bootstrap.Brick
33460 * @extends Roo.bootstrap.Component
33461 * Bootstrap Brick class
33464 * Create a new Brick
33465 * @param {Object} config The config object
33468 Roo.bootstrap.Brick = function(config){
33469 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33475 * When a Brick is click
33476 * @param {Roo.bootstrap.Brick} this
33477 * @param {Roo.EventObject} e
33483 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33486 * @cfg {String} title
33490 * @cfg {String} html
33494 * @cfg {String} bgimage
33498 * @cfg {String} cls
33502 * @cfg {String} href
33506 * @cfg {String} video
33510 * @cfg {Boolean} square
33514 getAutoCreate : function()
33516 var cls = 'roo-brick';
33518 if(this.href.length){
33519 cls += ' roo-brick-link';
33522 if(this.bgimage.length){
33523 cls += ' roo-brick-image';
33526 if(!this.html.length && !this.bgimage.length){
33527 cls += ' roo-brick-center-title';
33530 if(!this.html.length && this.bgimage.length){
33531 cls += ' roo-brick-bottom-title';
33535 cls += ' ' + this.cls;
33539 tag: (this.href.length) ? 'a' : 'div',
33544 cls: 'roo-brick-paragraph',
33550 if(this.href.length){
33551 cfg.href = this.href;
33554 var cn = cfg.cn[0].cn;
33556 if(this.title.length){
33559 cls: 'roo-brick-title',
33564 if(this.html.length){
33567 cls: 'roo-brick-text',
33574 if(this.bgimage.length){
33577 cls: 'roo-brick-image-view',
33585 initEvents: function()
33587 if(this.title.length || this.html.length){
33588 this.el.on('mouseenter' ,this.enter, this);
33589 this.el.on('mouseleave', this.leave, this);
33592 Roo.EventManager.onWindowResize(this.resize, this);
33594 if(this.bgimage.length){
33595 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33596 this.imageEl.on('load', this.onImageLoad, this);
33603 onImageLoad : function()
33608 resize : function()
33610 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33612 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33614 if(this.bgimage.length){
33615 var image = this.el.select('.roo-brick-image-view', true).first();
33617 image.setWidth(paragraph.getWidth());
33620 image.setHeight(paragraph.getWidth());
33623 this.el.setHeight(image.getHeight());
33624 paragraph.setHeight(image.getHeight());
33630 enter: function(e, el)
33632 e.preventDefault();
33634 if(this.bgimage.length){
33635 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33636 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33640 leave: function(e, el)
33642 e.preventDefault();
33644 if(this.bgimage.length){
33645 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33646 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33661 * @class Roo.bootstrap.NumberField
33662 * @extends Roo.bootstrap.Input
33663 * Bootstrap NumberField class
33669 * Create a new NumberField
33670 * @param {Object} config The config object
33673 Roo.bootstrap.NumberField = function(config){
33674 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33677 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33680 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33682 allowDecimals : true,
33684 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33686 decimalSeparator : ".",
33688 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33690 decimalPrecision : 2,
33692 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33694 allowNegative : true,
33697 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33701 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33703 minValue : Number.NEGATIVE_INFINITY,
33705 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33707 maxValue : Number.MAX_VALUE,
33709 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33711 minText : "The minimum value for this field is {0}",
33713 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33715 maxText : "The maximum value for this field is {0}",
33717 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33718 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33720 nanText : "{0} is not a valid number",
33722 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33724 thousandsDelimiter : false,
33726 * @cfg {String} valueAlign alignment of value
33728 valueAlign : "left",
33730 getAutoCreate : function()
33732 var hiddenInput = {
33736 cls: 'hidden-number-input'
33740 hiddenInput.name = this.name;
33745 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33747 this.name = hiddenInput.name;
33749 if(cfg.cn.length > 0) {
33750 cfg.cn.push(hiddenInput);
33757 initEvents : function()
33759 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33761 var allowed = "0123456789";
33763 if(this.allowDecimals){
33764 allowed += this.decimalSeparator;
33767 if(this.allowNegative){
33771 if(this.thousandsDelimiter) {
33775 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33777 var keyPress = function(e){
33779 var k = e.getKey();
33781 var c = e.getCharCode();
33784 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33785 allowed.indexOf(String.fromCharCode(c)) === -1
33791 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33795 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33800 this.el.on("keypress", keyPress, this);
33803 validateValue : function(value)
33806 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33810 var num = this.parseValue(value);
33813 this.markInvalid(String.format(this.nanText, value));
33817 if(num < this.minValue){
33818 this.markInvalid(String.format(this.minText, this.minValue));
33822 if(num > this.maxValue){
33823 this.markInvalid(String.format(this.maxText, this.maxValue));
33830 getValue : function()
33832 var v = this.hiddenEl().getValue();
33834 return this.fixPrecision(this.parseValue(v));
33837 parseValue : function(value)
33839 if(this.thousandsDelimiter) {
33841 r = new RegExp(",", "g");
33842 value = value.replace(r, "");
33845 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33846 return isNaN(value) ? '' : value;
33849 fixPrecision : function(value)
33851 if(this.thousandsDelimiter) {
33853 r = new RegExp(",", "g");
33854 value = value.replace(r, "");
33857 var nan = isNaN(value);
33859 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33860 return nan ? '' : value;
33862 return parseFloat(value).toFixed(this.decimalPrecision);
33865 setValue : function(v)
33867 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33873 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33875 this.inputEl().dom.value = (v == '') ? '' :
33876 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33878 if(!this.allowZero && v === '0') {
33879 this.hiddenEl().dom.value = '';
33880 this.inputEl().dom.value = '';
33887 decimalPrecisionFcn : function(v)
33889 return Math.floor(v);
33892 beforeBlur : function()
33894 var v = this.parseValue(this.getRawValue());
33896 if(v || v === 0 || v === ''){
33901 hiddenEl : function()
33903 return this.el.select('input.hidden-number-input',true).first();
33915 * @class Roo.bootstrap.DocumentSlider
33916 * @extends Roo.bootstrap.Component
33917 * Bootstrap DocumentSlider class
33920 * Create a new DocumentViewer
33921 * @param {Object} config The config object
33924 Roo.bootstrap.DocumentSlider = function(config){
33925 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33932 * Fire after initEvent
33933 * @param {Roo.bootstrap.DocumentSlider} this
33938 * Fire after update
33939 * @param {Roo.bootstrap.DocumentSlider} this
33945 * @param {Roo.bootstrap.DocumentSlider} this
33951 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33957 getAutoCreate : function()
33961 cls : 'roo-document-slider',
33965 cls : 'roo-document-slider-header',
33969 cls : 'roo-document-slider-header-title'
33975 cls : 'roo-document-slider-body',
33979 cls : 'roo-document-slider-prev',
33983 cls : 'fa fa-chevron-left'
33989 cls : 'roo-document-slider-thumb',
33993 cls : 'roo-document-slider-image'
33999 cls : 'roo-document-slider-next',
34003 cls : 'fa fa-chevron-right'
34015 initEvents : function()
34017 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34018 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34020 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34021 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34023 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34024 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34026 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34027 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34029 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34030 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34032 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34033 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34035 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34036 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34038 this.thumbEl.on('click', this.onClick, this);
34040 this.prevIndicator.on('click', this.prev, this);
34042 this.nextIndicator.on('click', this.next, this);
34046 initial : function()
34048 if(this.files.length){
34049 this.indicator = 1;
34053 this.fireEvent('initial', this);
34056 update : function()
34058 this.imageEl.attr('src', this.files[this.indicator - 1]);
34060 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34062 this.prevIndicator.show();
34064 if(this.indicator == 1){
34065 this.prevIndicator.hide();
34068 this.nextIndicator.show();
34070 if(this.indicator == this.files.length){
34071 this.nextIndicator.hide();
34074 this.thumbEl.scrollTo('top');
34076 this.fireEvent('update', this);
34079 onClick : function(e)
34081 e.preventDefault();
34083 this.fireEvent('click', this);
34088 e.preventDefault();
34090 this.indicator = Math.max(1, this.indicator - 1);
34097 e.preventDefault();
34099 this.indicator = Math.min(this.files.length, this.indicator + 1);
34113 * @class Roo.bootstrap.RadioSet
34114 * @extends Roo.bootstrap.Input
34115 * Bootstrap RadioSet class
34116 * @cfg {String} indicatorpos (left|right) default left
34117 * @cfg {Boolean} inline (true|false) inline the element (default true)
34118 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34120 * Create a new RadioSet
34121 * @param {Object} config The config object
34124 Roo.bootstrap.RadioSet = function(config){
34126 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34130 Roo.bootstrap.RadioSet.register(this);
34135 * Fires when the element is checked or unchecked.
34136 * @param {Roo.bootstrap.RadioSet} this This radio
34137 * @param {Roo.bootstrap.Radio} item The checked item
34142 * Fires when the element is click.
34143 * @param {Roo.bootstrap.RadioSet} this This radio set
34144 * @param {Roo.bootstrap.Radio} item The checked item
34145 * @param {Roo.EventObject} e The event object
34152 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34160 indicatorpos : 'left',
34162 getAutoCreate : function()
34166 cls : 'roo-radio-set-label',
34170 html : this.fieldLabel
34174 if (Roo.bootstrap.version == 3) {
34177 if(this.indicatorpos == 'left'){
34180 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34181 tooltip : 'This field is required'
34186 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34187 tooltip : 'This field is required'
34193 cls : 'roo-radio-set-items'
34196 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34198 if (align === 'left' && this.fieldLabel.length) {
34201 cls : "roo-radio-set-right",
34207 if(this.labelWidth > 12){
34208 label.style = "width: " + this.labelWidth + 'px';
34211 if(this.labelWidth < 13 && this.labelmd == 0){
34212 this.labelmd = this.labelWidth;
34215 if(this.labellg > 0){
34216 label.cls += ' col-lg-' + this.labellg;
34217 items.cls += ' col-lg-' + (12 - this.labellg);
34220 if(this.labelmd > 0){
34221 label.cls += ' col-md-' + this.labelmd;
34222 items.cls += ' col-md-' + (12 - this.labelmd);
34225 if(this.labelsm > 0){
34226 label.cls += ' col-sm-' + this.labelsm;
34227 items.cls += ' col-sm-' + (12 - this.labelsm);
34230 if(this.labelxs > 0){
34231 label.cls += ' col-xs-' + this.labelxs;
34232 items.cls += ' col-xs-' + (12 - this.labelxs);
34238 cls : 'roo-radio-set',
34242 cls : 'roo-radio-set-input',
34245 value : this.value ? this.value : ''
34252 if(this.weight.length){
34253 cfg.cls += ' roo-radio-' + this.weight;
34257 cfg.cls += ' roo-radio-set-inline';
34261 ['xs','sm','md','lg'].map(function(size){
34262 if (settings[size]) {
34263 cfg.cls += ' col-' + size + '-' + settings[size];
34271 initEvents : function()
34273 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34274 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34276 if(!this.fieldLabel.length){
34277 this.labelEl.hide();
34280 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34281 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34283 this.indicator = this.indicatorEl();
34285 if(this.indicator){
34286 this.indicator.addClass('invisible');
34289 this.originalValue = this.getValue();
34293 inputEl: function ()
34295 return this.el.select('.roo-radio-set-input', true).first();
34298 getChildContainer : function()
34300 return this.itemsEl;
34303 register : function(item)
34305 this.radioes.push(item);
34309 validate : function()
34311 if(this.getVisibilityEl().hasClass('hidden')){
34317 Roo.each(this.radioes, function(i){
34326 if(this.allowBlank) {
34330 if(this.disabled || valid){
34335 this.markInvalid();
34340 markValid : function()
34342 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34343 this.indicatorEl().removeClass('visible');
34344 this.indicatorEl().addClass('invisible');
34348 if (Roo.bootstrap.version == 3) {
34349 this.el.removeClass([this.invalidClass, this.validClass]);
34350 this.el.addClass(this.validClass);
34352 this.el.removeClass(['is-invalid','is-valid']);
34353 this.el.addClass(['is-valid']);
34355 this.fireEvent('valid', this);
34358 markInvalid : function(msg)
34360 if(this.allowBlank || this.disabled){
34364 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34365 this.indicatorEl().removeClass('invisible');
34366 this.indicatorEl().addClass('visible');
34368 if (Roo.bootstrap.version == 3) {
34369 this.el.removeClass([this.invalidClass, this.validClass]);
34370 this.el.addClass(this.invalidClass);
34372 this.el.removeClass(['is-invalid','is-valid']);
34373 this.el.addClass(['is-invalid']);
34376 this.fireEvent('invalid', this, msg);
34380 setValue : function(v, suppressEvent)
34382 if(this.value === v){
34389 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34392 Roo.each(this.radioes, function(i){
34394 i.el.removeClass('checked');
34397 Roo.each(this.radioes, function(i){
34399 if(i.value === v || i.value.toString() === v.toString()){
34401 i.el.addClass('checked');
34403 if(suppressEvent !== true){
34404 this.fireEvent('check', this, i);
34415 clearInvalid : function(){
34417 if(!this.el || this.preventMark){
34421 this.el.removeClass([this.invalidClass]);
34423 this.fireEvent('valid', this);
34428 Roo.apply(Roo.bootstrap.RadioSet, {
34432 register : function(set)
34434 this.groups[set.name] = set;
34437 get: function(name)
34439 if (typeof(this.groups[name]) == 'undefined') {
34443 return this.groups[name] ;
34449 * Ext JS Library 1.1.1
34450 * Copyright(c) 2006-2007, Ext JS, LLC.
34452 * Originally Released Under LGPL - original licence link has changed is not relivant.
34455 * <script type="text/javascript">
34460 * @class Roo.bootstrap.SplitBar
34461 * @extends Roo.util.Observable
34462 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34466 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34467 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34468 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34469 split.minSize = 100;
34470 split.maxSize = 600;
34471 split.animate = true;
34472 split.on('moved', splitterMoved);
34475 * Create a new SplitBar
34476 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34477 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34478 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34479 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34480 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34481 position of the SplitBar).
34483 Roo.bootstrap.SplitBar = function(cfg){
34488 // dragElement : elm
34489 // resizingElement: el,
34491 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34492 // placement : Roo.bootstrap.SplitBar.LEFT ,
34493 // existingProxy ???
34496 this.el = Roo.get(cfg.dragElement, true);
34497 this.el.dom.unselectable = "on";
34499 this.resizingEl = Roo.get(cfg.resizingElement, true);
34503 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34504 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34507 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34510 * The minimum size of the resizing element. (Defaults to 0)
34516 * The maximum size of the resizing element. (Defaults to 2000)
34519 this.maxSize = 2000;
34522 * Whether to animate the transition to the new size
34525 this.animate = false;
34528 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34531 this.useShim = false;
34536 if(!cfg.existingProxy){
34538 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34540 this.proxy = Roo.get(cfg.existingProxy).dom;
34543 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34546 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34549 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34552 this.dragSpecs = {};
34555 * @private The adapter to use to positon and resize elements
34557 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34558 this.adapter.init(this);
34560 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34562 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34563 this.el.addClass("roo-splitbar-h");
34566 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34567 this.el.addClass("roo-splitbar-v");
34573 * Fires when the splitter is moved (alias for {@link #event-moved})
34574 * @param {Roo.bootstrap.SplitBar} this
34575 * @param {Number} newSize the new width or height
34580 * Fires when the splitter is moved
34581 * @param {Roo.bootstrap.SplitBar} this
34582 * @param {Number} newSize the new width or height
34586 * @event beforeresize
34587 * Fires before the splitter is dragged
34588 * @param {Roo.bootstrap.SplitBar} this
34590 "beforeresize" : true,
34592 "beforeapply" : true
34595 Roo.util.Observable.call(this);
34598 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34599 onStartProxyDrag : function(x, y){
34600 this.fireEvent("beforeresize", this);
34602 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34604 o.enableDisplayMode("block");
34605 // all splitbars share the same overlay
34606 Roo.bootstrap.SplitBar.prototype.overlay = o;
34608 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34609 this.overlay.show();
34610 Roo.get(this.proxy).setDisplayed("block");
34611 var size = this.adapter.getElementSize(this);
34612 this.activeMinSize = this.getMinimumSize();;
34613 this.activeMaxSize = this.getMaximumSize();;
34614 var c1 = size - this.activeMinSize;
34615 var c2 = Math.max(this.activeMaxSize - size, 0);
34616 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34617 this.dd.resetConstraints();
34618 this.dd.setXConstraint(
34619 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34620 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34622 this.dd.setYConstraint(0, 0);
34624 this.dd.resetConstraints();
34625 this.dd.setXConstraint(0, 0);
34626 this.dd.setYConstraint(
34627 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34628 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34631 this.dragSpecs.startSize = size;
34632 this.dragSpecs.startPoint = [x, y];
34633 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34637 * @private Called after the drag operation by the DDProxy
34639 onEndProxyDrag : function(e){
34640 Roo.get(this.proxy).setDisplayed(false);
34641 var endPoint = Roo.lib.Event.getXY(e);
34643 this.overlay.hide();
34646 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34647 newSize = this.dragSpecs.startSize +
34648 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34649 endPoint[0] - this.dragSpecs.startPoint[0] :
34650 this.dragSpecs.startPoint[0] - endPoint[0]
34653 newSize = this.dragSpecs.startSize +
34654 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34655 endPoint[1] - this.dragSpecs.startPoint[1] :
34656 this.dragSpecs.startPoint[1] - endPoint[1]
34659 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34660 if(newSize != this.dragSpecs.startSize){
34661 if(this.fireEvent('beforeapply', this, newSize) !== false){
34662 this.adapter.setElementSize(this, newSize);
34663 this.fireEvent("moved", this, newSize);
34664 this.fireEvent("resize", this, newSize);
34670 * Get the adapter this SplitBar uses
34671 * @return The adapter object
34673 getAdapter : function(){
34674 return this.adapter;
34678 * Set the adapter this SplitBar uses
34679 * @param {Object} adapter A SplitBar adapter object
34681 setAdapter : function(adapter){
34682 this.adapter = adapter;
34683 this.adapter.init(this);
34687 * Gets the minimum size for the resizing element
34688 * @return {Number} The minimum size
34690 getMinimumSize : function(){
34691 return this.minSize;
34695 * Sets the minimum size for the resizing element
34696 * @param {Number} minSize The minimum size
34698 setMinimumSize : function(minSize){
34699 this.minSize = minSize;
34703 * Gets the maximum size for the resizing element
34704 * @return {Number} The maximum size
34706 getMaximumSize : function(){
34707 return this.maxSize;
34711 * Sets the maximum size for the resizing element
34712 * @param {Number} maxSize The maximum size
34714 setMaximumSize : function(maxSize){
34715 this.maxSize = maxSize;
34719 * Sets the initialize size for the resizing element
34720 * @param {Number} size The initial size
34722 setCurrentSize : function(size){
34723 var oldAnimate = this.animate;
34724 this.animate = false;
34725 this.adapter.setElementSize(this, size);
34726 this.animate = oldAnimate;
34730 * Destroy this splitbar.
34731 * @param {Boolean} removeEl True to remove the element
34733 destroy : function(removeEl){
34735 this.shim.remove();
34738 this.proxy.parentNode.removeChild(this.proxy);
34746 * @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.
34748 Roo.bootstrap.SplitBar.createProxy = function(dir){
34749 var proxy = new Roo.Element(document.createElement("div"));
34750 proxy.unselectable();
34751 var cls = 'roo-splitbar-proxy';
34752 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34753 document.body.appendChild(proxy.dom);
34758 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34759 * Default Adapter. It assumes the splitter and resizing element are not positioned
34760 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34762 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34765 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34766 // do nothing for now
34767 init : function(s){
34771 * Called before drag operations to get the current size of the resizing element.
34772 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34774 getElementSize : function(s){
34775 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34776 return s.resizingEl.getWidth();
34778 return s.resizingEl.getHeight();
34783 * Called after drag operations to set the size of the resizing element.
34784 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34785 * @param {Number} newSize The new size to set
34786 * @param {Function} onComplete A function to be invoked when resizing is complete
34788 setElementSize : function(s, newSize, onComplete){
34789 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34791 s.resizingEl.setWidth(newSize);
34793 onComplete(s, newSize);
34796 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34801 s.resizingEl.setHeight(newSize);
34803 onComplete(s, newSize);
34806 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34813 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34814 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34815 * Adapter that moves the splitter element to align with the resized sizing element.
34816 * Used with an absolute positioned SplitBar.
34817 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34818 * document.body, make sure you assign an id to the body element.
34820 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34821 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34822 this.container = Roo.get(container);
34825 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34826 init : function(s){
34827 this.basic.init(s);
34830 getElementSize : function(s){
34831 return this.basic.getElementSize(s);
34834 setElementSize : function(s, newSize, onComplete){
34835 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34838 moveSplitter : function(s){
34839 var yes = Roo.bootstrap.SplitBar;
34840 switch(s.placement){
34842 s.el.setX(s.resizingEl.getRight());
34845 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34848 s.el.setY(s.resizingEl.getBottom());
34851 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34858 * Orientation constant - Create a vertical SplitBar
34862 Roo.bootstrap.SplitBar.VERTICAL = 1;
34865 * Orientation constant - Create a horizontal SplitBar
34869 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34872 * Placement constant - The resizing element is to the left of the splitter element
34876 Roo.bootstrap.SplitBar.LEFT = 1;
34879 * Placement constant - The resizing element is to the right of the splitter element
34883 Roo.bootstrap.SplitBar.RIGHT = 2;
34886 * Placement constant - The resizing element is positioned above the splitter element
34890 Roo.bootstrap.SplitBar.TOP = 3;
34893 * Placement constant - The resizing element is positioned under splitter element
34897 Roo.bootstrap.SplitBar.BOTTOM = 4;
34898 Roo.namespace("Roo.bootstrap.layout");/*
34900 * Ext JS Library 1.1.1
34901 * Copyright(c) 2006-2007, Ext JS, LLC.
34903 * Originally Released Under LGPL - original licence link has changed is not relivant.
34906 * <script type="text/javascript">
34910 * @class Roo.bootstrap.layout.Manager
34911 * @extends Roo.bootstrap.Component
34912 * Base class for layout managers.
34914 Roo.bootstrap.layout.Manager = function(config)
34916 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34922 /** false to disable window resize monitoring @type Boolean */
34923 this.monitorWindowResize = true;
34928 * Fires when a layout is performed.
34929 * @param {Roo.LayoutManager} this
34933 * @event regionresized
34934 * Fires when the user resizes a region.
34935 * @param {Roo.LayoutRegion} region The resized region
34936 * @param {Number} newSize The new size (width for east/west, height for north/south)
34938 "regionresized" : true,
34940 * @event regioncollapsed
34941 * Fires when a region is collapsed.
34942 * @param {Roo.LayoutRegion} region The collapsed region
34944 "regioncollapsed" : true,
34946 * @event regionexpanded
34947 * Fires when a region is expanded.
34948 * @param {Roo.LayoutRegion} region The expanded region
34950 "regionexpanded" : true
34952 this.updating = false;
34955 this.el = Roo.get(config.el);
34961 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34966 monitorWindowResize : true,
34972 onRender : function(ct, position)
34975 this.el = Roo.get(ct);
34978 //this.fireEvent('render',this);
34982 initEvents: function()
34986 // ie scrollbar fix
34987 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34988 document.body.scroll = "no";
34989 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34990 this.el.position('relative');
34992 this.id = this.el.id;
34993 this.el.addClass("roo-layout-container");
34994 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34995 if(this.el.dom != document.body ) {
34996 this.el.on('resize', this.layout,this);
34997 this.el.on('show', this.layout,this);
35003 * Returns true if this layout is currently being updated
35004 * @return {Boolean}
35006 isUpdating : function(){
35007 return this.updating;
35011 * Suspend the LayoutManager from doing auto-layouts while
35012 * making multiple add or remove calls
35014 beginUpdate : function(){
35015 this.updating = true;
35019 * Restore auto-layouts and optionally disable the manager from performing a layout
35020 * @param {Boolean} noLayout true to disable a layout update
35022 endUpdate : function(noLayout){
35023 this.updating = false;
35029 layout: function(){
35033 onRegionResized : function(region, newSize){
35034 this.fireEvent("regionresized", region, newSize);
35038 onRegionCollapsed : function(region){
35039 this.fireEvent("regioncollapsed", region);
35042 onRegionExpanded : function(region){
35043 this.fireEvent("regionexpanded", region);
35047 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35048 * performs box-model adjustments.
35049 * @return {Object} The size as an object {width: (the width), height: (the height)}
35051 getViewSize : function()
35054 if(this.el.dom != document.body){
35055 size = this.el.getSize();
35057 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35059 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35060 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35065 * Returns the Element this layout is bound to.
35066 * @return {Roo.Element}
35068 getEl : function(){
35073 * Returns the specified region.
35074 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35075 * @return {Roo.LayoutRegion}
35077 getRegion : function(target){
35078 return this.regions[target.toLowerCase()];
35081 onWindowResize : function(){
35082 if(this.monitorWindowResize){
35089 * Ext JS Library 1.1.1
35090 * Copyright(c) 2006-2007, Ext JS, LLC.
35092 * Originally Released Under LGPL - original licence link has changed is not relivant.
35095 * <script type="text/javascript">
35098 * @class Roo.bootstrap.layout.Border
35099 * @extends Roo.bootstrap.layout.Manager
35100 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35101 * please see: examples/bootstrap/nested.html<br><br>
35103 <b>The container the layout is rendered into can be either the body element or any other element.
35104 If it is not the body element, the container needs to either be an absolute positioned element,
35105 or you will need to add "position:relative" to the css of the container. You will also need to specify
35106 the container size if it is not the body element.</b>
35109 * Create a new Border
35110 * @param {Object} config Configuration options
35112 Roo.bootstrap.layout.Border = function(config){
35113 config = config || {};
35114 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35118 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35119 if(config[region]){
35120 config[region].region = region;
35121 this.addRegion(config[region]);
35127 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35129 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35131 parent : false, // this might point to a 'nest' or a ???
35134 * Creates and adds a new region if it doesn't already exist.
35135 * @param {String} target The target region key (north, south, east, west or center).
35136 * @param {Object} config The regions config object
35137 * @return {BorderLayoutRegion} The new region
35139 addRegion : function(config)
35141 if(!this.regions[config.region]){
35142 var r = this.factory(config);
35143 this.bindRegion(r);
35145 return this.regions[config.region];
35149 bindRegion : function(r){
35150 this.regions[r.config.region] = r;
35152 r.on("visibilitychange", this.layout, this);
35153 r.on("paneladded", this.layout, this);
35154 r.on("panelremoved", this.layout, this);
35155 r.on("invalidated", this.layout, this);
35156 r.on("resized", this.onRegionResized, this);
35157 r.on("collapsed", this.onRegionCollapsed, this);
35158 r.on("expanded", this.onRegionExpanded, this);
35162 * Performs a layout update.
35164 layout : function()
35166 if(this.updating) {
35170 // render all the rebions if they have not been done alreayd?
35171 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35172 if(this.regions[region] && !this.regions[region].bodyEl){
35173 this.regions[region].onRender(this.el)
35177 var size = this.getViewSize();
35178 var w = size.width;
35179 var h = size.height;
35184 //var x = 0, y = 0;
35186 var rs = this.regions;
35187 var north = rs["north"];
35188 var south = rs["south"];
35189 var west = rs["west"];
35190 var east = rs["east"];
35191 var center = rs["center"];
35192 //if(this.hideOnLayout){ // not supported anymore
35193 //c.el.setStyle("display", "none");
35195 if(north && north.isVisible()){
35196 var b = north.getBox();
35197 var m = north.getMargins();
35198 b.width = w - (m.left+m.right);
35201 centerY = b.height + b.y + m.bottom;
35202 centerH -= centerY;
35203 north.updateBox(this.safeBox(b));
35205 if(south && south.isVisible()){
35206 var b = south.getBox();
35207 var m = south.getMargins();
35208 b.width = w - (m.left+m.right);
35210 var totalHeight = (b.height + m.top + m.bottom);
35211 b.y = h - totalHeight + m.top;
35212 centerH -= totalHeight;
35213 south.updateBox(this.safeBox(b));
35215 if(west && west.isVisible()){
35216 var b = west.getBox();
35217 var m = west.getMargins();
35218 b.height = centerH - (m.top+m.bottom);
35220 b.y = centerY + m.top;
35221 var totalWidth = (b.width + m.left + m.right);
35222 centerX += totalWidth;
35223 centerW -= totalWidth;
35224 west.updateBox(this.safeBox(b));
35226 if(east && east.isVisible()){
35227 var b = east.getBox();
35228 var m = east.getMargins();
35229 b.height = centerH - (m.top+m.bottom);
35230 var totalWidth = (b.width + m.left + m.right);
35231 b.x = w - totalWidth + m.left;
35232 b.y = centerY + m.top;
35233 centerW -= totalWidth;
35234 east.updateBox(this.safeBox(b));
35237 var m = center.getMargins();
35239 x: centerX + m.left,
35240 y: centerY + m.top,
35241 width: centerW - (m.left+m.right),
35242 height: centerH - (m.top+m.bottom)
35244 //if(this.hideOnLayout){
35245 //center.el.setStyle("display", "block");
35247 center.updateBox(this.safeBox(centerBox));
35250 this.fireEvent("layout", this);
35254 safeBox : function(box){
35255 box.width = Math.max(0, box.width);
35256 box.height = Math.max(0, box.height);
35261 * Adds a ContentPanel (or subclass) to this layout.
35262 * @param {String} target The target region key (north, south, east, west or center).
35263 * @param {Roo.ContentPanel} panel The panel to add
35264 * @return {Roo.ContentPanel} The added panel
35266 add : function(target, panel){
35268 target = target.toLowerCase();
35269 return this.regions[target].add(panel);
35273 * Remove a ContentPanel (or subclass) to this layout.
35274 * @param {String} target The target region key (north, south, east, west or center).
35275 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35276 * @return {Roo.ContentPanel} The removed panel
35278 remove : function(target, panel){
35279 target = target.toLowerCase();
35280 return this.regions[target].remove(panel);
35284 * Searches all regions for a panel with the specified id
35285 * @param {String} panelId
35286 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35288 findPanel : function(panelId){
35289 var rs = this.regions;
35290 for(var target in rs){
35291 if(typeof rs[target] != "function"){
35292 var p = rs[target].getPanel(panelId);
35302 * Searches all regions for a panel with the specified id and activates (shows) it.
35303 * @param {String/ContentPanel} panelId The panels id or the panel itself
35304 * @return {Roo.ContentPanel} The shown panel or null
35306 showPanel : function(panelId) {
35307 var rs = this.regions;
35308 for(var target in rs){
35309 var r = rs[target];
35310 if(typeof r != "function"){
35311 if(r.hasPanel(panelId)){
35312 return r.showPanel(panelId);
35320 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35321 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35324 restoreState : function(provider){
35326 provider = Roo.state.Manager;
35328 var sm = new Roo.LayoutStateManager();
35329 sm.init(this, provider);
35335 * Adds a xtype elements to the layout.
35339 xtype : 'ContentPanel',
35346 xtype : 'NestedLayoutPanel',
35352 items : [ ... list of content panels or nested layout panels.. ]
35356 * @param {Object} cfg Xtype definition of item to add.
35358 addxtype : function(cfg)
35360 // basically accepts a pannel...
35361 // can accept a layout region..!?!?
35362 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35365 // theory? children can only be panels??
35367 //if (!cfg.xtype.match(/Panel$/)) {
35372 if (typeof(cfg.region) == 'undefined') {
35373 Roo.log("Failed to add Panel, region was not set");
35377 var region = cfg.region;
35383 xitems = cfg.items;
35388 if ( region == 'center') {
35389 Roo.log("Center: " + cfg.title);
35395 case 'Content': // ContentPanel (el, cfg)
35396 case 'Scroll': // ContentPanel (el, cfg)
35398 cfg.autoCreate = cfg.autoCreate || true;
35399 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35401 // var el = this.el.createChild();
35402 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35405 this.add(region, ret);
35409 case 'TreePanel': // our new panel!
35410 cfg.el = this.el.createChild();
35411 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35412 this.add(region, ret);
35417 // create a new Layout (which is a Border Layout...
35419 var clayout = cfg.layout;
35420 clayout.el = this.el.createChild();
35421 clayout.items = clayout.items || [];
35425 // replace this exitems with the clayout ones..
35426 xitems = clayout.items;
35428 // force background off if it's in center...
35429 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35430 cfg.background = false;
35432 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35435 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35436 //console.log('adding nested layout panel ' + cfg.toSource());
35437 this.add(region, ret);
35438 nb = {}; /// find first...
35443 // needs grid and region
35445 //var el = this.getRegion(region).el.createChild();
35447 *var el = this.el.createChild();
35448 // create the grid first...
35449 cfg.grid.container = el;
35450 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35453 if (region == 'center' && this.active ) {
35454 cfg.background = false;
35457 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35459 this.add(region, ret);
35461 if (cfg.background) {
35462 // render grid on panel activation (if panel background)
35463 ret.on('activate', function(gp) {
35464 if (!gp.grid.rendered) {
35465 // gp.grid.render(el);
35469 // cfg.grid.render(el);
35475 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35476 // it was the old xcomponent building that caused this before.
35477 // espeically if border is the top element in the tree.
35487 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35489 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35490 this.add(region, ret);
35494 throw "Can not add '" + cfg.xtype + "' to Border";
35500 this.beginUpdate();
35504 Roo.each(xitems, function(i) {
35505 region = nb && i.region ? i.region : false;
35507 var add = ret.addxtype(i);
35510 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35511 if (!i.background) {
35512 abn[region] = nb[region] ;
35519 // make the last non-background panel active..
35520 //if (nb) { Roo.log(abn); }
35523 for(var r in abn) {
35524 region = this.getRegion(r);
35526 // tried using nb[r], but it does not work..
35528 region.showPanel(abn[r]);
35539 factory : function(cfg)
35542 var validRegions = Roo.bootstrap.layout.Border.regions;
35544 var target = cfg.region;
35547 var r = Roo.bootstrap.layout;
35551 return new r.North(cfg);
35553 return new r.South(cfg);
35555 return new r.East(cfg);
35557 return new r.West(cfg);
35559 return new r.Center(cfg);
35561 throw 'Layout region "'+target+'" not supported.';
35568 * Ext JS Library 1.1.1
35569 * Copyright(c) 2006-2007, Ext JS, LLC.
35571 * Originally Released Under LGPL - original licence link has changed is not relivant.
35574 * <script type="text/javascript">
35578 * @class Roo.bootstrap.layout.Basic
35579 * @extends Roo.util.Observable
35580 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35581 * and does not have a titlebar, tabs or any other features. All it does is size and position
35582 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35583 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35584 * @cfg {string} region the region that it inhabits..
35585 * @cfg {bool} skipConfig skip config?
35589 Roo.bootstrap.layout.Basic = function(config){
35591 this.mgr = config.mgr;
35593 this.position = config.region;
35595 var skipConfig = config.skipConfig;
35599 * @scope Roo.BasicLayoutRegion
35603 * @event beforeremove
35604 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35605 * @param {Roo.LayoutRegion} this
35606 * @param {Roo.ContentPanel} panel The panel
35607 * @param {Object} e The cancel event object
35609 "beforeremove" : true,
35611 * @event invalidated
35612 * Fires when the layout for this region is changed.
35613 * @param {Roo.LayoutRegion} this
35615 "invalidated" : true,
35617 * @event visibilitychange
35618 * Fires when this region is shown or hidden
35619 * @param {Roo.LayoutRegion} this
35620 * @param {Boolean} visibility true or false
35622 "visibilitychange" : true,
35624 * @event paneladded
35625 * Fires when a panel is added.
35626 * @param {Roo.LayoutRegion} this
35627 * @param {Roo.ContentPanel} panel The panel
35629 "paneladded" : true,
35631 * @event panelremoved
35632 * Fires when a panel is removed.
35633 * @param {Roo.LayoutRegion} this
35634 * @param {Roo.ContentPanel} panel The panel
35636 "panelremoved" : true,
35638 * @event beforecollapse
35639 * Fires when this region before collapse.
35640 * @param {Roo.LayoutRegion} this
35642 "beforecollapse" : true,
35645 * Fires when this region is collapsed.
35646 * @param {Roo.LayoutRegion} this
35648 "collapsed" : true,
35651 * Fires when this region is expanded.
35652 * @param {Roo.LayoutRegion} this
35657 * Fires when this region is slid into view.
35658 * @param {Roo.LayoutRegion} this
35660 "slideshow" : true,
35663 * Fires when this region slides out of view.
35664 * @param {Roo.LayoutRegion} this
35666 "slidehide" : true,
35668 * @event panelactivated
35669 * Fires when a panel is activated.
35670 * @param {Roo.LayoutRegion} this
35671 * @param {Roo.ContentPanel} panel The activated panel
35673 "panelactivated" : true,
35676 * Fires when the user resizes this region.
35677 * @param {Roo.LayoutRegion} this
35678 * @param {Number} newSize The new size (width for east/west, height for north/south)
35682 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35683 this.panels = new Roo.util.MixedCollection();
35684 this.panels.getKey = this.getPanelId.createDelegate(this);
35686 this.activePanel = null;
35687 // ensure listeners are added...
35689 if (config.listeners || config.events) {
35690 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35691 listeners : config.listeners || {},
35692 events : config.events || {}
35696 if(skipConfig !== true){
35697 this.applyConfig(config);
35701 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35703 getPanelId : function(p){
35707 applyConfig : function(config){
35708 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35709 this.config = config;
35714 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35715 * the width, for horizontal (north, south) the height.
35716 * @param {Number} newSize The new width or height
35718 resizeTo : function(newSize){
35719 var el = this.el ? this.el :
35720 (this.activePanel ? this.activePanel.getEl() : null);
35722 switch(this.position){
35725 el.setWidth(newSize);
35726 this.fireEvent("resized", this, newSize);
35730 el.setHeight(newSize);
35731 this.fireEvent("resized", this, newSize);
35737 getBox : function(){
35738 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35741 getMargins : function(){
35742 return this.margins;
35745 updateBox : function(box){
35747 var el = this.activePanel.getEl();
35748 el.dom.style.left = box.x + "px";
35749 el.dom.style.top = box.y + "px";
35750 this.activePanel.setSize(box.width, box.height);
35754 * Returns the container element for this region.
35755 * @return {Roo.Element}
35757 getEl : function(){
35758 return this.activePanel;
35762 * Returns true if this region is currently visible.
35763 * @return {Boolean}
35765 isVisible : function(){
35766 return this.activePanel ? true : false;
35769 setActivePanel : function(panel){
35770 panel = this.getPanel(panel);
35771 if(this.activePanel && this.activePanel != panel){
35772 this.activePanel.setActiveState(false);
35773 this.activePanel.getEl().setLeftTop(-10000,-10000);
35775 this.activePanel = panel;
35776 panel.setActiveState(true);
35778 panel.setSize(this.box.width, this.box.height);
35780 this.fireEvent("panelactivated", this, panel);
35781 this.fireEvent("invalidated");
35785 * Show the specified panel.
35786 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35787 * @return {Roo.ContentPanel} The shown panel or null
35789 showPanel : function(panel){
35790 panel = this.getPanel(panel);
35792 this.setActivePanel(panel);
35798 * Get the active panel for this region.
35799 * @return {Roo.ContentPanel} The active panel or null
35801 getActivePanel : function(){
35802 return this.activePanel;
35806 * Add the passed ContentPanel(s)
35807 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35808 * @return {Roo.ContentPanel} The panel added (if only one was added)
35810 add : function(panel){
35811 if(arguments.length > 1){
35812 for(var i = 0, len = arguments.length; i < len; i++) {
35813 this.add(arguments[i]);
35817 if(this.hasPanel(panel)){
35818 this.showPanel(panel);
35821 var el = panel.getEl();
35822 if(el.dom.parentNode != this.mgr.el.dom){
35823 this.mgr.el.dom.appendChild(el.dom);
35825 if(panel.setRegion){
35826 panel.setRegion(this);
35828 this.panels.add(panel);
35829 el.setStyle("position", "absolute");
35830 if(!panel.background){
35831 this.setActivePanel(panel);
35832 if(this.config.initialSize && this.panels.getCount()==1){
35833 this.resizeTo(this.config.initialSize);
35836 this.fireEvent("paneladded", this, panel);
35841 * Returns true if the panel is in this region.
35842 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35843 * @return {Boolean}
35845 hasPanel : function(panel){
35846 if(typeof panel == "object"){ // must be panel obj
35847 panel = panel.getId();
35849 return this.getPanel(panel) ? true : false;
35853 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35854 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35855 * @param {Boolean} preservePanel Overrides the config preservePanel option
35856 * @return {Roo.ContentPanel} The panel that was removed
35858 remove : function(panel, preservePanel){
35859 panel = this.getPanel(panel);
35864 this.fireEvent("beforeremove", this, panel, e);
35865 if(e.cancel === true){
35868 var panelId = panel.getId();
35869 this.panels.removeKey(panelId);
35874 * Returns the panel specified or null if it's not in this region.
35875 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35876 * @return {Roo.ContentPanel}
35878 getPanel : function(id){
35879 if(typeof id == "object"){ // must be panel obj
35882 return this.panels.get(id);
35886 * Returns this regions position (north/south/east/west/center).
35889 getPosition: function(){
35890 return this.position;
35894 * Ext JS Library 1.1.1
35895 * Copyright(c) 2006-2007, Ext JS, LLC.
35897 * Originally Released Under LGPL - original licence link has changed is not relivant.
35900 * <script type="text/javascript">
35904 * @class Roo.bootstrap.layout.Region
35905 * @extends Roo.bootstrap.layout.Basic
35906 * This class represents a region in a layout manager.
35908 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35909 * @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})
35910 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35911 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35912 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35913 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35914 * @cfg {String} title The title for the region (overrides panel titles)
35915 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35916 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35917 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35918 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35919 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35920 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35921 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35922 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35923 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35924 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35926 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35927 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35928 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35929 * @cfg {Number} width For East/West panels
35930 * @cfg {Number} height For North/South panels
35931 * @cfg {Boolean} split To show the splitter
35932 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35934 * @cfg {string} cls Extra CSS classes to add to region
35936 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35937 * @cfg {string} region the region that it inhabits..
35940 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35941 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35943 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35944 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35945 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35947 Roo.bootstrap.layout.Region = function(config)
35949 this.applyConfig(config);
35951 var mgr = config.mgr;
35952 var pos = config.region;
35953 config.skipConfig = true;
35954 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35957 this.onRender(mgr.el);
35960 this.visible = true;
35961 this.collapsed = false;
35962 this.unrendered_panels = [];
35965 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35967 position: '', // set by wrapper (eg. north/south etc..)
35968 unrendered_panels : null, // unrendered panels.
35970 tabPosition : false,
35972 mgr: false, // points to 'Border'
35975 createBody : function(){
35976 /** This region's body element
35977 * @type Roo.Element */
35978 this.bodyEl = this.el.createChild({
35980 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35984 onRender: function(ctr, pos)
35986 var dh = Roo.DomHelper;
35987 /** This region's container element
35988 * @type Roo.Element */
35989 this.el = dh.append(ctr.dom, {
35991 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35993 /** This region's title element
35994 * @type Roo.Element */
35996 this.titleEl = dh.append(this.el.dom, {
35998 unselectable: "on",
35999 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36001 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36002 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36006 this.titleEl.enableDisplayMode();
36007 /** This region's title text element
36008 * @type HTMLElement */
36009 this.titleTextEl = this.titleEl.dom.firstChild;
36010 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36012 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36013 this.closeBtn.enableDisplayMode();
36014 this.closeBtn.on("click", this.closeClicked, this);
36015 this.closeBtn.hide();
36017 this.createBody(this.config);
36018 if(this.config.hideWhenEmpty){
36020 this.on("paneladded", this.validateVisibility, this);
36021 this.on("panelremoved", this.validateVisibility, this);
36023 if(this.autoScroll){
36024 this.bodyEl.setStyle("overflow", "auto");
36026 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36028 //if(c.titlebar !== false){
36029 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36030 this.titleEl.hide();
36032 this.titleEl.show();
36033 if(this.config.title){
36034 this.titleTextEl.innerHTML = this.config.title;
36038 if(this.config.collapsed){
36039 this.collapse(true);
36041 if(this.config.hidden){
36045 if (this.unrendered_panels && this.unrendered_panels.length) {
36046 for (var i =0;i< this.unrendered_panels.length; i++) {
36047 this.add(this.unrendered_panels[i]);
36049 this.unrendered_panels = null;
36055 applyConfig : function(c)
36058 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36059 var dh = Roo.DomHelper;
36060 if(c.titlebar !== false){
36061 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36062 this.collapseBtn.on("click", this.collapse, this);
36063 this.collapseBtn.enableDisplayMode();
36065 if(c.showPin === true || this.showPin){
36066 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36067 this.stickBtn.enableDisplayMode();
36068 this.stickBtn.on("click", this.expand, this);
36069 this.stickBtn.hide();
36074 /** This region's collapsed element
36075 * @type Roo.Element */
36078 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36079 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36082 if(c.floatable !== false){
36083 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36084 this.collapsedEl.on("click", this.collapseClick, this);
36087 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36088 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36089 id: "message", unselectable: "on", style:{"float":"left"}});
36090 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36092 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36093 this.expandBtn.on("click", this.expand, this);
36097 if(this.collapseBtn){
36098 this.collapseBtn.setVisible(c.collapsible == true);
36101 this.cmargins = c.cmargins || this.cmargins ||
36102 (this.position == "west" || this.position == "east" ?
36103 {top: 0, left: 2, right:2, bottom: 0} :
36104 {top: 2, left: 0, right:0, bottom: 2});
36106 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36109 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36111 this.autoScroll = c.autoScroll || false;
36116 this.duration = c.duration || .30;
36117 this.slideDuration = c.slideDuration || .45;
36122 * Returns true if this region is currently visible.
36123 * @return {Boolean}
36125 isVisible : function(){
36126 return this.visible;
36130 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36131 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36133 //setCollapsedTitle : function(title){
36134 // title = title || " ";
36135 // if(this.collapsedTitleTextEl){
36136 // this.collapsedTitleTextEl.innerHTML = title;
36140 getBox : function(){
36142 // if(!this.collapsed){
36143 b = this.el.getBox(false, true);
36145 // b = this.collapsedEl.getBox(false, true);
36150 getMargins : function(){
36151 return this.margins;
36152 //return this.collapsed ? this.cmargins : this.margins;
36155 highlight : function(){
36156 this.el.addClass("x-layout-panel-dragover");
36159 unhighlight : function(){
36160 this.el.removeClass("x-layout-panel-dragover");
36163 updateBox : function(box)
36165 if (!this.bodyEl) {
36166 return; // not rendered yet..
36170 if(!this.collapsed){
36171 this.el.dom.style.left = box.x + "px";
36172 this.el.dom.style.top = box.y + "px";
36173 this.updateBody(box.width, box.height);
36175 this.collapsedEl.dom.style.left = box.x + "px";
36176 this.collapsedEl.dom.style.top = box.y + "px";
36177 this.collapsedEl.setSize(box.width, box.height);
36180 this.tabs.autoSizeTabs();
36184 updateBody : function(w, h)
36187 this.el.setWidth(w);
36188 w -= this.el.getBorderWidth("rl");
36189 if(this.config.adjustments){
36190 w += this.config.adjustments[0];
36193 if(h !== null && h > 0){
36194 this.el.setHeight(h);
36195 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36196 h -= this.el.getBorderWidth("tb");
36197 if(this.config.adjustments){
36198 h += this.config.adjustments[1];
36200 this.bodyEl.setHeight(h);
36202 h = this.tabs.syncHeight(h);
36205 if(this.panelSize){
36206 w = w !== null ? w : this.panelSize.width;
36207 h = h !== null ? h : this.panelSize.height;
36209 if(this.activePanel){
36210 var el = this.activePanel.getEl();
36211 w = w !== null ? w : el.getWidth();
36212 h = h !== null ? h : el.getHeight();
36213 this.panelSize = {width: w, height: h};
36214 this.activePanel.setSize(w, h);
36216 if(Roo.isIE && this.tabs){
36217 this.tabs.el.repaint();
36222 * Returns the container element for this region.
36223 * @return {Roo.Element}
36225 getEl : function(){
36230 * Hides this region.
36233 //if(!this.collapsed){
36234 this.el.dom.style.left = "-2000px";
36237 // this.collapsedEl.dom.style.left = "-2000px";
36238 // this.collapsedEl.hide();
36240 this.visible = false;
36241 this.fireEvent("visibilitychange", this, false);
36245 * Shows this region if it was previously hidden.
36248 //if(!this.collapsed){
36251 // this.collapsedEl.show();
36253 this.visible = true;
36254 this.fireEvent("visibilitychange", this, true);
36257 closeClicked : function(){
36258 if(this.activePanel){
36259 this.remove(this.activePanel);
36263 collapseClick : function(e){
36265 e.stopPropagation();
36268 e.stopPropagation();
36274 * Collapses this region.
36275 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36278 collapse : function(skipAnim, skipCheck = false){
36279 if(this.collapsed) {
36283 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36285 this.collapsed = true;
36287 this.split.el.hide();
36289 if(this.config.animate && skipAnim !== true){
36290 this.fireEvent("invalidated", this);
36291 this.animateCollapse();
36293 this.el.setLocation(-20000,-20000);
36295 this.collapsedEl.show();
36296 this.fireEvent("collapsed", this);
36297 this.fireEvent("invalidated", this);
36303 animateCollapse : function(){
36308 * Expands this region if it was previously collapsed.
36309 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36310 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36313 expand : function(e, skipAnim){
36315 e.stopPropagation();
36317 if(!this.collapsed || this.el.hasActiveFx()) {
36321 this.afterSlideIn();
36324 this.collapsed = false;
36325 if(this.config.animate && skipAnim !== true){
36326 this.animateExpand();
36330 this.split.el.show();
36332 this.collapsedEl.setLocation(-2000,-2000);
36333 this.collapsedEl.hide();
36334 this.fireEvent("invalidated", this);
36335 this.fireEvent("expanded", this);
36339 animateExpand : function(){
36343 initTabs : function()
36345 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36347 var ts = new Roo.bootstrap.panel.Tabs({
36348 el: this.bodyEl.dom,
36350 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36351 disableTooltips: this.config.disableTabTips,
36352 toolbar : this.config.toolbar
36355 if(this.config.hideTabs){
36356 ts.stripWrap.setDisplayed(false);
36359 ts.resizeTabs = this.config.resizeTabs === true;
36360 ts.minTabWidth = this.config.minTabWidth || 40;
36361 ts.maxTabWidth = this.config.maxTabWidth || 250;
36362 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36363 ts.monitorResize = false;
36364 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36365 ts.bodyEl.addClass('roo-layout-tabs-body');
36366 this.panels.each(this.initPanelAsTab, this);
36369 initPanelAsTab : function(panel){
36370 var ti = this.tabs.addTab(
36374 this.config.closeOnTab && panel.isClosable(),
36377 if(panel.tabTip !== undefined){
36378 ti.setTooltip(panel.tabTip);
36380 ti.on("activate", function(){
36381 this.setActivePanel(panel);
36384 if(this.config.closeOnTab){
36385 ti.on("beforeclose", function(t, e){
36387 this.remove(panel);
36391 panel.tabItem = ti;
36396 updatePanelTitle : function(panel, title)
36398 if(this.activePanel == panel){
36399 this.updateTitle(title);
36402 var ti = this.tabs.getTab(panel.getEl().id);
36404 if(panel.tabTip !== undefined){
36405 ti.setTooltip(panel.tabTip);
36410 updateTitle : function(title){
36411 if(this.titleTextEl && !this.config.title){
36412 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36416 setActivePanel : function(panel)
36418 panel = this.getPanel(panel);
36419 if(this.activePanel && this.activePanel != panel){
36420 if(this.activePanel.setActiveState(false) === false){
36424 this.activePanel = panel;
36425 panel.setActiveState(true);
36426 if(this.panelSize){
36427 panel.setSize(this.panelSize.width, this.panelSize.height);
36430 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36432 this.updateTitle(panel.getTitle());
36434 this.fireEvent("invalidated", this);
36436 this.fireEvent("panelactivated", this, panel);
36440 * Shows the specified panel.
36441 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36442 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36444 showPanel : function(panel)
36446 panel = this.getPanel(panel);
36449 var tab = this.tabs.getTab(panel.getEl().id);
36450 if(tab.isHidden()){
36451 this.tabs.unhideTab(tab.id);
36455 this.setActivePanel(panel);
36462 * Get the active panel for this region.
36463 * @return {Roo.ContentPanel} The active panel or null
36465 getActivePanel : function(){
36466 return this.activePanel;
36469 validateVisibility : function(){
36470 if(this.panels.getCount() < 1){
36471 this.updateTitle(" ");
36472 this.closeBtn.hide();
36475 if(!this.isVisible()){
36482 * Adds the passed ContentPanel(s) to this region.
36483 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36484 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36486 add : function(panel)
36488 if(arguments.length > 1){
36489 for(var i = 0, len = arguments.length; i < len; i++) {
36490 this.add(arguments[i]);
36495 // if we have not been rendered yet, then we can not really do much of this..
36496 if (!this.bodyEl) {
36497 this.unrendered_panels.push(panel);
36504 if(this.hasPanel(panel)){
36505 this.showPanel(panel);
36508 panel.setRegion(this);
36509 this.panels.add(panel);
36510 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36511 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36512 // and hide them... ???
36513 this.bodyEl.dom.appendChild(panel.getEl().dom);
36514 if(panel.background !== true){
36515 this.setActivePanel(panel);
36517 this.fireEvent("paneladded", this, panel);
36524 this.initPanelAsTab(panel);
36528 if(panel.background !== true){
36529 this.tabs.activate(panel.getEl().id);
36531 this.fireEvent("paneladded", this, panel);
36536 * Hides the tab for the specified panel.
36537 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36539 hidePanel : function(panel){
36540 if(this.tabs && (panel = this.getPanel(panel))){
36541 this.tabs.hideTab(panel.getEl().id);
36546 * Unhides the tab for a previously hidden panel.
36547 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36549 unhidePanel : function(panel){
36550 if(this.tabs && (panel = this.getPanel(panel))){
36551 this.tabs.unhideTab(panel.getEl().id);
36555 clearPanels : function(){
36556 while(this.panels.getCount() > 0){
36557 this.remove(this.panels.first());
36562 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36563 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36564 * @param {Boolean} preservePanel Overrides the config preservePanel option
36565 * @return {Roo.ContentPanel} The panel that was removed
36567 remove : function(panel, preservePanel)
36569 panel = this.getPanel(panel);
36574 this.fireEvent("beforeremove", this, panel, e);
36575 if(e.cancel === true){
36578 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36579 var panelId = panel.getId();
36580 this.panels.removeKey(panelId);
36582 document.body.appendChild(panel.getEl().dom);
36585 this.tabs.removeTab(panel.getEl().id);
36586 }else if (!preservePanel){
36587 this.bodyEl.dom.removeChild(panel.getEl().dom);
36589 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36590 var p = this.panels.first();
36591 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36592 tempEl.appendChild(p.getEl().dom);
36593 this.bodyEl.update("");
36594 this.bodyEl.dom.appendChild(p.getEl().dom);
36596 this.updateTitle(p.getTitle());
36598 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36599 this.setActivePanel(p);
36601 panel.setRegion(null);
36602 if(this.activePanel == panel){
36603 this.activePanel = null;
36605 if(this.config.autoDestroy !== false && preservePanel !== true){
36606 try{panel.destroy();}catch(e){}
36608 this.fireEvent("panelremoved", this, panel);
36613 * Returns the TabPanel component used by this region
36614 * @return {Roo.TabPanel}
36616 getTabs : function(){
36620 createTool : function(parentEl, className){
36621 var btn = Roo.DomHelper.append(parentEl, {
36623 cls: "x-layout-tools-button",
36626 cls: "roo-layout-tools-button-inner " + className,
36630 btn.addClassOnOver("roo-layout-tools-button-over");
36635 * Ext JS Library 1.1.1
36636 * Copyright(c) 2006-2007, Ext JS, LLC.
36638 * Originally Released Under LGPL - original licence link has changed is not relivant.
36641 * <script type="text/javascript">
36647 * @class Roo.SplitLayoutRegion
36648 * @extends Roo.LayoutRegion
36649 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36651 Roo.bootstrap.layout.Split = function(config){
36652 this.cursor = config.cursor;
36653 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36656 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36658 splitTip : "Drag to resize.",
36659 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36660 useSplitTips : false,
36662 applyConfig : function(config){
36663 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36666 onRender : function(ctr,pos) {
36668 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36669 if(!this.config.split){
36674 var splitEl = Roo.DomHelper.append(ctr.dom, {
36676 id: this.el.id + "-split",
36677 cls: "roo-layout-split roo-layout-split-"+this.position,
36680 /** The SplitBar for this region
36681 * @type Roo.SplitBar */
36682 // does not exist yet...
36683 Roo.log([this.position, this.orientation]);
36685 this.split = new Roo.bootstrap.SplitBar({
36686 dragElement : splitEl,
36687 resizingElement: this.el,
36688 orientation : this.orientation
36691 this.split.on("moved", this.onSplitMove, this);
36692 this.split.useShim = this.config.useShim === true;
36693 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36694 if(this.useSplitTips){
36695 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36697 //if(config.collapsible){
36698 // this.split.el.on("dblclick", this.collapse, this);
36701 if(typeof this.config.minSize != "undefined"){
36702 this.split.minSize = this.config.minSize;
36704 if(typeof this.config.maxSize != "undefined"){
36705 this.split.maxSize = this.config.maxSize;
36707 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36708 this.hideSplitter();
36713 getHMaxSize : function(){
36714 var cmax = this.config.maxSize || 10000;
36715 var center = this.mgr.getRegion("center");
36716 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36719 getVMaxSize : function(){
36720 var cmax = this.config.maxSize || 10000;
36721 var center = this.mgr.getRegion("center");
36722 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36725 onSplitMove : function(split, newSize){
36726 this.fireEvent("resized", this, newSize);
36730 * Returns the {@link Roo.SplitBar} for this region.
36731 * @return {Roo.SplitBar}
36733 getSplitBar : function(){
36738 this.hideSplitter();
36739 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36742 hideSplitter : function(){
36744 this.split.el.setLocation(-2000,-2000);
36745 this.split.el.hide();
36751 this.split.el.show();
36753 Roo.bootstrap.layout.Split.superclass.show.call(this);
36756 beforeSlide: function(){
36757 if(Roo.isGecko){// firefox overflow auto bug workaround
36758 this.bodyEl.clip();
36760 this.tabs.bodyEl.clip();
36762 if(this.activePanel){
36763 this.activePanel.getEl().clip();
36765 if(this.activePanel.beforeSlide){
36766 this.activePanel.beforeSlide();
36772 afterSlide : function(){
36773 if(Roo.isGecko){// firefox overflow auto bug workaround
36774 this.bodyEl.unclip();
36776 this.tabs.bodyEl.unclip();
36778 if(this.activePanel){
36779 this.activePanel.getEl().unclip();
36780 if(this.activePanel.afterSlide){
36781 this.activePanel.afterSlide();
36787 initAutoHide : function(){
36788 if(this.autoHide !== false){
36789 if(!this.autoHideHd){
36790 var st = new Roo.util.DelayedTask(this.slideIn, this);
36791 this.autoHideHd = {
36792 "mouseout": function(e){
36793 if(!e.within(this.el, true)){
36797 "mouseover" : function(e){
36803 this.el.on(this.autoHideHd);
36807 clearAutoHide : function(){
36808 if(this.autoHide !== false){
36809 this.el.un("mouseout", this.autoHideHd.mouseout);
36810 this.el.un("mouseover", this.autoHideHd.mouseover);
36814 clearMonitor : function(){
36815 Roo.get(document).un("click", this.slideInIf, this);
36818 // these names are backwards but not changed for compat
36819 slideOut : function(){
36820 if(this.isSlid || this.el.hasActiveFx()){
36823 this.isSlid = true;
36824 if(this.collapseBtn){
36825 this.collapseBtn.hide();
36827 this.closeBtnState = this.closeBtn.getStyle('display');
36828 this.closeBtn.hide();
36830 this.stickBtn.show();
36833 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36834 this.beforeSlide();
36835 this.el.setStyle("z-index", 10001);
36836 this.el.slideIn(this.getSlideAnchor(), {
36837 callback: function(){
36839 this.initAutoHide();
36840 Roo.get(document).on("click", this.slideInIf, this);
36841 this.fireEvent("slideshow", this);
36848 afterSlideIn : function(){
36849 this.clearAutoHide();
36850 this.isSlid = false;
36851 this.clearMonitor();
36852 this.el.setStyle("z-index", "");
36853 if(this.collapseBtn){
36854 this.collapseBtn.show();
36856 this.closeBtn.setStyle('display', this.closeBtnState);
36858 this.stickBtn.hide();
36860 this.fireEvent("slidehide", this);
36863 slideIn : function(cb){
36864 if(!this.isSlid || this.el.hasActiveFx()){
36868 this.isSlid = false;
36869 this.beforeSlide();
36870 this.el.slideOut(this.getSlideAnchor(), {
36871 callback: function(){
36872 this.el.setLeftTop(-10000, -10000);
36874 this.afterSlideIn();
36882 slideInIf : function(e){
36883 if(!e.within(this.el)){
36888 animateCollapse : function(){
36889 this.beforeSlide();
36890 this.el.setStyle("z-index", 20000);
36891 var anchor = this.getSlideAnchor();
36892 this.el.slideOut(anchor, {
36893 callback : function(){
36894 this.el.setStyle("z-index", "");
36895 this.collapsedEl.slideIn(anchor, {duration:.3});
36897 this.el.setLocation(-10000,-10000);
36899 this.fireEvent("collapsed", this);
36906 animateExpand : function(){
36907 this.beforeSlide();
36908 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36909 this.el.setStyle("z-index", 20000);
36910 this.collapsedEl.hide({
36913 this.el.slideIn(this.getSlideAnchor(), {
36914 callback : function(){
36915 this.el.setStyle("z-index", "");
36918 this.split.el.show();
36920 this.fireEvent("invalidated", this);
36921 this.fireEvent("expanded", this);
36949 getAnchor : function(){
36950 return this.anchors[this.position];
36953 getCollapseAnchor : function(){
36954 return this.canchors[this.position];
36957 getSlideAnchor : function(){
36958 return this.sanchors[this.position];
36961 getAlignAdj : function(){
36962 var cm = this.cmargins;
36963 switch(this.position){
36979 getExpandAdj : function(){
36980 var c = this.collapsedEl, cm = this.cmargins;
36981 switch(this.position){
36983 return [-(cm.right+c.getWidth()+cm.left), 0];
36986 return [cm.right+c.getWidth()+cm.left, 0];
36989 return [0, -(cm.top+cm.bottom+c.getHeight())];
36992 return [0, cm.top+cm.bottom+c.getHeight()];
36998 * Ext JS Library 1.1.1
36999 * Copyright(c) 2006-2007, Ext JS, LLC.
37001 * Originally Released Under LGPL - original licence link has changed is not relivant.
37004 * <script type="text/javascript">
37007 * These classes are private internal classes
37009 Roo.bootstrap.layout.Center = function(config){
37010 config.region = "center";
37011 Roo.bootstrap.layout.Region.call(this, config);
37012 this.visible = true;
37013 this.minWidth = config.minWidth || 20;
37014 this.minHeight = config.minHeight || 20;
37017 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37019 // center panel can't be hidden
37023 // center panel can't be hidden
37026 getMinWidth: function(){
37027 return this.minWidth;
37030 getMinHeight: function(){
37031 return this.minHeight;
37045 Roo.bootstrap.layout.North = function(config)
37047 config.region = 'north';
37048 config.cursor = 'n-resize';
37050 Roo.bootstrap.layout.Split.call(this, config);
37054 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37055 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37056 this.split.el.addClass("roo-layout-split-v");
37058 var size = config.initialSize || config.height;
37059 if(typeof size != "undefined"){
37060 this.el.setHeight(size);
37063 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37065 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37069 getBox : function(){
37070 if(this.collapsed){
37071 return this.collapsedEl.getBox();
37073 var box = this.el.getBox();
37075 box.height += this.split.el.getHeight();
37080 updateBox : function(box){
37081 if(this.split && !this.collapsed){
37082 box.height -= this.split.el.getHeight();
37083 this.split.el.setLeft(box.x);
37084 this.split.el.setTop(box.y+box.height);
37085 this.split.el.setWidth(box.width);
37087 if(this.collapsed){
37088 this.updateBody(box.width, null);
37090 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37098 Roo.bootstrap.layout.South = function(config){
37099 config.region = 'south';
37100 config.cursor = 's-resize';
37101 Roo.bootstrap.layout.Split.call(this, config);
37103 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37104 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37105 this.split.el.addClass("roo-layout-split-v");
37107 var size = config.initialSize || config.height;
37108 if(typeof size != "undefined"){
37109 this.el.setHeight(size);
37113 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37114 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37115 getBox : function(){
37116 if(this.collapsed){
37117 return this.collapsedEl.getBox();
37119 var box = this.el.getBox();
37121 var sh = this.split.el.getHeight();
37128 updateBox : function(box){
37129 if(this.split && !this.collapsed){
37130 var sh = this.split.el.getHeight();
37133 this.split.el.setLeft(box.x);
37134 this.split.el.setTop(box.y-sh);
37135 this.split.el.setWidth(box.width);
37137 if(this.collapsed){
37138 this.updateBody(box.width, null);
37140 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37144 Roo.bootstrap.layout.East = function(config){
37145 config.region = "east";
37146 config.cursor = "e-resize";
37147 Roo.bootstrap.layout.Split.call(this, config);
37149 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37150 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37151 this.split.el.addClass("roo-layout-split-h");
37153 var size = config.initialSize || config.width;
37154 if(typeof size != "undefined"){
37155 this.el.setWidth(size);
37158 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37159 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37160 getBox : function(){
37161 if(this.collapsed){
37162 return this.collapsedEl.getBox();
37164 var box = this.el.getBox();
37166 var sw = this.split.el.getWidth();
37173 updateBox : function(box){
37174 if(this.split && !this.collapsed){
37175 var sw = this.split.el.getWidth();
37177 this.split.el.setLeft(box.x);
37178 this.split.el.setTop(box.y);
37179 this.split.el.setHeight(box.height);
37182 if(this.collapsed){
37183 this.updateBody(null, box.height);
37185 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37189 Roo.bootstrap.layout.West = function(config){
37190 config.region = "west";
37191 config.cursor = "w-resize";
37193 Roo.bootstrap.layout.Split.call(this, config);
37195 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37196 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37197 this.split.el.addClass("roo-layout-split-h");
37201 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37202 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37204 onRender: function(ctr, pos)
37206 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37207 var size = this.config.initialSize || this.config.width;
37208 if(typeof size != "undefined"){
37209 this.el.setWidth(size);
37213 getBox : function(){
37214 if(this.collapsed){
37215 return this.collapsedEl.getBox();
37217 var box = this.el.getBox();
37219 box.width += this.split.el.getWidth();
37224 updateBox : function(box){
37225 if(this.split && !this.collapsed){
37226 var sw = this.split.el.getWidth();
37228 this.split.el.setLeft(box.x+box.width);
37229 this.split.el.setTop(box.y);
37230 this.split.el.setHeight(box.height);
37232 if(this.collapsed){
37233 this.updateBody(null, box.height);
37235 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37237 });Roo.namespace("Roo.bootstrap.panel");/*
37239 * Ext JS Library 1.1.1
37240 * Copyright(c) 2006-2007, Ext JS, LLC.
37242 * Originally Released Under LGPL - original licence link has changed is not relivant.
37245 * <script type="text/javascript">
37248 * @class Roo.ContentPanel
37249 * @extends Roo.util.Observable
37250 * A basic ContentPanel element.
37251 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37252 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37253 * @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
37254 * @cfg {Boolean} closable True if the panel can be closed/removed
37255 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37256 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37257 * @cfg {Toolbar} toolbar A toolbar for this panel
37258 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37259 * @cfg {String} title The title for this panel
37260 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37261 * @cfg {String} url Calls {@link #setUrl} with this value
37262 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37263 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37264 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37265 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37266 * @cfg {Boolean} badges render the badges
37269 * Create a new ContentPanel.
37270 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37271 * @param {String/Object} config A string to set only the title or a config object
37272 * @param {String} content (optional) Set the HTML content for this panel
37273 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37275 Roo.bootstrap.panel.Content = function( config){
37277 this.tpl = config.tpl || false;
37279 var el = config.el;
37280 var content = config.content;
37282 if(config.autoCreate){ // xtype is available if this is called from factory
37285 this.el = Roo.get(el);
37286 if(!this.el && config && config.autoCreate){
37287 if(typeof config.autoCreate == "object"){
37288 if(!config.autoCreate.id){
37289 config.autoCreate.id = config.id||el;
37291 this.el = Roo.DomHelper.append(document.body,
37292 config.autoCreate, true);
37294 var elcfg = { tag: "div",
37295 cls: "roo-layout-inactive-content",
37299 elcfg.html = config.html;
37303 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37306 this.closable = false;
37307 this.loaded = false;
37308 this.active = false;
37311 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37313 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37315 this.wrapEl = this.el; //this.el.wrap();
37317 if (config.toolbar.items) {
37318 ti = config.toolbar.items ;
37319 delete config.toolbar.items ;
37323 this.toolbar.render(this.wrapEl, 'before');
37324 for(var i =0;i < ti.length;i++) {
37325 // Roo.log(['add child', items[i]]);
37326 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37328 this.toolbar.items = nitems;
37329 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37330 delete config.toolbar;
37334 // xtype created footer. - not sure if will work as we normally have to render first..
37335 if (this.footer && !this.footer.el && this.footer.xtype) {
37336 if (!this.wrapEl) {
37337 this.wrapEl = this.el.wrap();
37340 this.footer.container = this.wrapEl.createChild();
37342 this.footer = Roo.factory(this.footer, Roo);
37347 if(typeof config == "string"){
37348 this.title = config;
37350 Roo.apply(this, config);
37354 this.resizeEl = Roo.get(this.resizeEl, true);
37356 this.resizeEl = this.el;
37358 // handle view.xtype
37366 * Fires when this panel is activated.
37367 * @param {Roo.ContentPanel} this
37371 * @event deactivate
37372 * Fires when this panel is activated.
37373 * @param {Roo.ContentPanel} this
37375 "deactivate" : true,
37379 * Fires when this panel is resized if fitToFrame is true.
37380 * @param {Roo.ContentPanel} this
37381 * @param {Number} width The width after any component adjustments
37382 * @param {Number} height The height after any component adjustments
37388 * Fires when this tab is created
37389 * @param {Roo.ContentPanel} this
37400 if(this.autoScroll){
37401 this.resizeEl.setStyle("overflow", "auto");
37403 // fix randome scrolling
37404 //this.el.on('scroll', function() {
37405 // Roo.log('fix random scolling');
37406 // this.scrollTo('top',0);
37409 content = content || this.content;
37411 this.setContent(content);
37413 if(config && config.url){
37414 this.setUrl(this.url, this.params, this.loadOnce);
37419 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37421 if (this.view && typeof(this.view.xtype) != 'undefined') {
37422 this.view.el = this.el.appendChild(document.createElement("div"));
37423 this.view = Roo.factory(this.view);
37424 this.view.render && this.view.render(false, '');
37428 this.fireEvent('render', this);
37431 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37435 setRegion : function(region){
37436 this.region = region;
37437 this.setActiveClass(region && !this.background);
37441 setActiveClass: function(state)
37444 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37445 this.el.setStyle('position','relative');
37447 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37448 this.el.setStyle('position', 'absolute');
37453 * Returns the toolbar for this Panel if one was configured.
37454 * @return {Roo.Toolbar}
37456 getToolbar : function(){
37457 return this.toolbar;
37460 setActiveState : function(active)
37462 this.active = active;
37463 this.setActiveClass(active);
37465 if(this.fireEvent("deactivate", this) === false){
37470 this.fireEvent("activate", this);
37474 * Updates this panel's element
37475 * @param {String} content The new content
37476 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37478 setContent : function(content, loadScripts){
37479 this.el.update(content, loadScripts);
37482 ignoreResize : function(w, h){
37483 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37486 this.lastSize = {width: w, height: h};
37491 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37492 * @return {Roo.UpdateManager} The UpdateManager
37494 getUpdateManager : function(){
37495 return this.el.getUpdateManager();
37498 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37499 * @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:
37502 url: "your-url.php",
37503 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37504 callback: yourFunction,
37505 scope: yourObject, //(optional scope)
37508 text: "Loading...",
37513 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37514 * 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.
37515 * @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}
37516 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37517 * @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.
37518 * @return {Roo.ContentPanel} this
37521 var um = this.el.getUpdateManager();
37522 um.update.apply(um, arguments);
37528 * 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.
37529 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37530 * @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)
37531 * @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)
37532 * @return {Roo.UpdateManager} The UpdateManager
37534 setUrl : function(url, params, loadOnce){
37535 if(this.refreshDelegate){
37536 this.removeListener("activate", this.refreshDelegate);
37538 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37539 this.on("activate", this.refreshDelegate);
37540 return this.el.getUpdateManager();
37543 _handleRefresh : function(url, params, loadOnce){
37544 if(!loadOnce || !this.loaded){
37545 var updater = this.el.getUpdateManager();
37546 updater.update(url, params, this._setLoaded.createDelegate(this));
37550 _setLoaded : function(){
37551 this.loaded = true;
37555 * Returns this panel's id
37558 getId : function(){
37563 * Returns this panel's element - used by regiosn to add.
37564 * @return {Roo.Element}
37566 getEl : function(){
37567 return this.wrapEl || this.el;
37572 adjustForComponents : function(width, height)
37574 //Roo.log('adjustForComponents ');
37575 if(this.resizeEl != this.el){
37576 width -= this.el.getFrameWidth('lr');
37577 height -= this.el.getFrameWidth('tb');
37580 var te = this.toolbar.getEl();
37581 te.setWidth(width);
37582 height -= te.getHeight();
37585 var te = this.footer.getEl();
37586 te.setWidth(width);
37587 height -= te.getHeight();
37591 if(this.adjustments){
37592 width += this.adjustments[0];
37593 height += this.adjustments[1];
37595 return {"width": width, "height": height};
37598 setSize : function(width, height){
37599 if(this.fitToFrame && !this.ignoreResize(width, height)){
37600 if(this.fitContainer && this.resizeEl != this.el){
37601 this.el.setSize(width, height);
37603 var size = this.adjustForComponents(width, height);
37604 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37605 this.fireEvent('resize', this, size.width, size.height);
37610 * Returns this panel's title
37613 getTitle : function(){
37615 if (typeof(this.title) != 'object') {
37620 for (var k in this.title) {
37621 if (!this.title.hasOwnProperty(k)) {
37625 if (k.indexOf('-') >= 0) {
37626 var s = k.split('-');
37627 for (var i = 0; i<s.length; i++) {
37628 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37631 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37638 * Set this panel's title
37639 * @param {String} title
37641 setTitle : function(title){
37642 this.title = title;
37644 this.region.updatePanelTitle(this, title);
37649 * Returns true is this panel was configured to be closable
37650 * @return {Boolean}
37652 isClosable : function(){
37653 return this.closable;
37656 beforeSlide : function(){
37658 this.resizeEl.clip();
37661 afterSlide : function(){
37663 this.resizeEl.unclip();
37667 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37668 * Will fail silently if the {@link #setUrl} method has not been called.
37669 * This does not activate the panel, just updates its content.
37671 refresh : function(){
37672 if(this.refreshDelegate){
37673 this.loaded = false;
37674 this.refreshDelegate();
37679 * Destroys this panel
37681 destroy : function(){
37682 this.el.removeAllListeners();
37683 var tempEl = document.createElement("span");
37684 tempEl.appendChild(this.el.dom);
37685 tempEl.innerHTML = "";
37691 * form - if the content panel contains a form - this is a reference to it.
37692 * @type {Roo.form.Form}
37696 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37697 * This contains a reference to it.
37703 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37713 * @param {Object} cfg Xtype definition of item to add.
37717 getChildContainer: function () {
37718 return this.getEl();
37723 var ret = new Roo.factory(cfg);
37728 if (cfg.xtype.match(/^Form$/)) {
37731 //if (this.footer) {
37732 // el = this.footer.container.insertSibling(false, 'before');
37734 el = this.el.createChild();
37737 this.form = new Roo.form.Form(cfg);
37740 if ( this.form.allItems.length) {
37741 this.form.render(el.dom);
37745 // should only have one of theses..
37746 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37747 // views.. should not be just added - used named prop 'view''
37749 cfg.el = this.el.appendChild(document.createElement("div"));
37752 var ret = new Roo.factory(cfg);
37754 ret.render && ret.render(false, ''); // render blank..
37764 * @class Roo.bootstrap.panel.Grid
37765 * @extends Roo.bootstrap.panel.Content
37767 * Create a new GridPanel.
37768 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37769 * @param {Object} config A the config object
37775 Roo.bootstrap.panel.Grid = function(config)
37779 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37780 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37782 config.el = this.wrapper;
37783 //this.el = this.wrapper;
37785 if (config.container) {
37786 // ctor'ed from a Border/panel.grid
37789 this.wrapper.setStyle("overflow", "hidden");
37790 this.wrapper.addClass('roo-grid-container');
37795 if(config.toolbar){
37796 var tool_el = this.wrapper.createChild();
37797 this.toolbar = Roo.factory(config.toolbar);
37799 if (config.toolbar.items) {
37800 ti = config.toolbar.items ;
37801 delete config.toolbar.items ;
37805 this.toolbar.render(tool_el);
37806 for(var i =0;i < ti.length;i++) {
37807 // Roo.log(['add child', items[i]]);
37808 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37810 this.toolbar.items = nitems;
37812 delete config.toolbar;
37815 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37816 config.grid.scrollBody = true;;
37817 config.grid.monitorWindowResize = false; // turn off autosizing
37818 config.grid.autoHeight = false;
37819 config.grid.autoWidth = false;
37821 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37823 if (config.background) {
37824 // render grid on panel activation (if panel background)
37825 this.on('activate', function(gp) {
37826 if (!gp.grid.rendered) {
37827 gp.grid.render(this.wrapper);
37828 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37833 this.grid.render(this.wrapper);
37834 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37837 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37838 // ??? needed ??? config.el = this.wrapper;
37843 // xtype created footer. - not sure if will work as we normally have to render first..
37844 if (this.footer && !this.footer.el && this.footer.xtype) {
37846 var ctr = this.grid.getView().getFooterPanel(true);
37847 this.footer.dataSource = this.grid.dataSource;
37848 this.footer = Roo.factory(this.footer, Roo);
37849 this.footer.render(ctr);
37859 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37860 getId : function(){
37861 return this.grid.id;
37865 * Returns the grid for this panel
37866 * @return {Roo.bootstrap.Table}
37868 getGrid : function(){
37872 setSize : function(width, height){
37873 if(!this.ignoreResize(width, height)){
37874 var grid = this.grid;
37875 var size = this.adjustForComponents(width, height);
37876 var gridel = grid.getGridEl();
37877 gridel.setSize(size.width, size.height);
37879 var thd = grid.getGridEl().select('thead',true).first();
37880 var tbd = grid.getGridEl().select('tbody', true).first();
37882 tbd.setSize(width, height - thd.getHeight());
37891 beforeSlide : function(){
37892 this.grid.getView().scroller.clip();
37895 afterSlide : function(){
37896 this.grid.getView().scroller.unclip();
37899 destroy : function(){
37900 this.grid.destroy();
37902 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37907 * @class Roo.bootstrap.panel.Nest
37908 * @extends Roo.bootstrap.panel.Content
37910 * Create a new Panel, that can contain a layout.Border.
37913 * @param {Roo.BorderLayout} layout The layout for this panel
37914 * @param {String/Object} config A string to set only the title or a config object
37916 Roo.bootstrap.panel.Nest = function(config)
37918 // construct with only one argument..
37919 /* FIXME - implement nicer consturctors
37920 if (layout.layout) {
37922 layout = config.layout;
37923 delete config.layout;
37925 if (layout.xtype && !layout.getEl) {
37926 // then layout needs constructing..
37927 layout = Roo.factory(layout, Roo);
37931 config.el = config.layout.getEl();
37933 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37935 config.layout.monitorWindowResize = false; // turn off autosizing
37936 this.layout = config.layout;
37937 this.layout.getEl().addClass("roo-layout-nested-layout");
37938 this.layout.parent = this;
37945 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37947 setSize : function(width, height){
37948 if(!this.ignoreResize(width, height)){
37949 var size = this.adjustForComponents(width, height);
37950 var el = this.layout.getEl();
37951 if (size.height < 1) {
37952 el.setWidth(size.width);
37954 el.setSize(size.width, size.height);
37956 var touch = el.dom.offsetWidth;
37957 this.layout.layout();
37958 // ie requires a double layout on the first pass
37959 if(Roo.isIE && !this.initialized){
37960 this.initialized = true;
37961 this.layout.layout();
37966 // activate all subpanels if not currently active..
37968 setActiveState : function(active){
37969 this.active = active;
37970 this.setActiveClass(active);
37973 this.fireEvent("deactivate", this);
37977 this.fireEvent("activate", this);
37978 // not sure if this should happen before or after..
37979 if (!this.layout) {
37980 return; // should not happen..
37983 for (var r in this.layout.regions) {
37984 reg = this.layout.getRegion(r);
37985 if (reg.getActivePanel()) {
37986 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37987 reg.setActivePanel(reg.getActivePanel());
37990 if (!reg.panels.length) {
37993 reg.showPanel(reg.getPanel(0));
38002 * Returns the nested BorderLayout for this panel
38003 * @return {Roo.BorderLayout}
38005 getLayout : function(){
38006 return this.layout;
38010 * Adds a xtype elements to the layout of the nested panel
38014 xtype : 'ContentPanel',
38021 xtype : 'NestedLayoutPanel',
38027 items : [ ... list of content panels or nested layout panels.. ]
38031 * @param {Object} cfg Xtype definition of item to add.
38033 addxtype : function(cfg) {
38034 return this.layout.addxtype(cfg);
38039 * Ext JS Library 1.1.1
38040 * Copyright(c) 2006-2007, Ext JS, LLC.
38042 * Originally Released Under LGPL - original licence link has changed is not relivant.
38045 * <script type="text/javascript">
38048 * @class Roo.TabPanel
38049 * @extends Roo.util.Observable
38050 * A lightweight tab container.
38054 // basic tabs 1, built from existing content
38055 var tabs = new Roo.TabPanel("tabs1");
38056 tabs.addTab("script", "View Script");
38057 tabs.addTab("markup", "View Markup");
38058 tabs.activate("script");
38060 // more advanced tabs, built from javascript
38061 var jtabs = new Roo.TabPanel("jtabs");
38062 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38064 // set up the UpdateManager
38065 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38066 var updater = tab2.getUpdateManager();
38067 updater.setDefaultUrl("ajax1.htm");
38068 tab2.on('activate', updater.refresh, updater, true);
38070 // Use setUrl for Ajax loading
38071 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38072 tab3.setUrl("ajax2.htm", null, true);
38075 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38078 jtabs.activate("jtabs-1");
38081 * Create a new TabPanel.
38082 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38083 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38085 Roo.bootstrap.panel.Tabs = function(config){
38087 * The container element for this TabPanel.
38088 * @type Roo.Element
38090 this.el = Roo.get(config.el);
38093 if(typeof config == "boolean"){
38094 this.tabPosition = config ? "bottom" : "top";
38096 Roo.apply(this, config);
38100 if(this.tabPosition == "bottom"){
38101 // if tabs are at the bottom = create the body first.
38102 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38103 this.el.addClass("roo-tabs-bottom");
38105 // next create the tabs holders
38107 if (this.tabPosition == "west"){
38109 var reg = this.region; // fake it..
38111 if (!reg.mgr.parent) {
38114 reg = reg.mgr.parent.region;
38116 Roo.log("got nest?");
38118 if (reg.mgr.getRegion('west')) {
38119 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38120 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38121 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38122 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38123 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38131 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38132 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38133 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38134 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38139 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38142 // finally - if tabs are at the top, then create the body last..
38143 if(this.tabPosition != "bottom"){
38144 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38145 * @type Roo.Element
38147 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38148 this.el.addClass("roo-tabs-top");
38152 this.bodyEl.setStyle("position", "relative");
38154 this.active = null;
38155 this.activateDelegate = this.activate.createDelegate(this);
38160 * Fires when the active tab changes
38161 * @param {Roo.TabPanel} this
38162 * @param {Roo.TabPanelItem} activePanel The new active tab
38166 * @event beforetabchange
38167 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38168 * @param {Roo.TabPanel} this
38169 * @param {Object} e Set cancel to true on this object to cancel the tab change
38170 * @param {Roo.TabPanelItem} tab The tab being changed to
38172 "beforetabchange" : true
38175 Roo.EventManager.onWindowResize(this.onResize, this);
38176 this.cpad = this.el.getPadding("lr");
38177 this.hiddenCount = 0;
38180 // toolbar on the tabbar support...
38181 if (this.toolbar) {
38182 alert("no toolbar support yet");
38183 this.toolbar = false;
38185 var tcfg = this.toolbar;
38186 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38187 this.toolbar = new Roo.Toolbar(tcfg);
38188 if (Roo.isSafari) {
38189 var tbl = tcfg.container.child('table', true);
38190 tbl.setAttribute('width', '100%');
38198 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38201 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38203 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38205 tabPosition : "top",
38207 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38209 currentTabWidth : 0,
38211 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38215 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38219 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38221 preferredTabWidth : 175,
38223 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38225 resizeTabs : false,
38227 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38229 monitorResize : true,
38231 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38233 toolbar : false, // set by caller..
38235 region : false, /// set by caller
38237 disableTooltips : true, // not used yet...
38240 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38241 * @param {String} id The id of the div to use <b>or create</b>
38242 * @param {String} text The text for the tab
38243 * @param {String} content (optional) Content to put in the TabPanelItem body
38244 * @param {Boolean} closable (optional) True to create a close icon on the tab
38245 * @return {Roo.TabPanelItem} The created TabPanelItem
38247 addTab : function(id, text, content, closable, tpl)
38249 var item = new Roo.bootstrap.panel.TabItem({
38253 closable : closable,
38256 this.addTabItem(item);
38258 item.setContent(content);
38264 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38265 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38266 * @return {Roo.TabPanelItem}
38268 getTab : function(id){
38269 return this.items[id];
38273 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38274 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38276 hideTab : function(id){
38277 var t = this.items[id];
38280 this.hiddenCount++;
38281 this.autoSizeTabs();
38286 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38287 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38289 unhideTab : function(id){
38290 var t = this.items[id];
38292 t.setHidden(false);
38293 this.hiddenCount--;
38294 this.autoSizeTabs();
38299 * Adds an existing {@link Roo.TabPanelItem}.
38300 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38302 addTabItem : function(item)
38304 this.items[item.id] = item;
38305 this.items.push(item);
38306 this.autoSizeTabs();
38307 // if(this.resizeTabs){
38308 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38309 // this.autoSizeTabs();
38311 // item.autoSize();
38316 * Removes a {@link Roo.TabPanelItem}.
38317 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38319 removeTab : function(id){
38320 var items = this.items;
38321 var tab = items[id];
38322 if(!tab) { return; }
38323 var index = items.indexOf(tab);
38324 if(this.active == tab && items.length > 1){
38325 var newTab = this.getNextAvailable(index);
38330 this.stripEl.dom.removeChild(tab.pnode.dom);
38331 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38332 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38334 items.splice(index, 1);
38335 delete this.items[tab.id];
38336 tab.fireEvent("close", tab);
38337 tab.purgeListeners();
38338 this.autoSizeTabs();
38341 getNextAvailable : function(start){
38342 var items = this.items;
38344 // look for a next tab that will slide over to
38345 // replace the one being removed
38346 while(index < items.length){
38347 var item = items[++index];
38348 if(item && !item.isHidden()){
38352 // if one isn't found select the previous tab (on the left)
38355 var item = items[--index];
38356 if(item && !item.isHidden()){
38364 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38365 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38367 disableTab : function(id){
38368 var tab = this.items[id];
38369 if(tab && this.active != tab){
38375 * Enables a {@link Roo.TabPanelItem} that is disabled.
38376 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38378 enableTab : function(id){
38379 var tab = this.items[id];
38384 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38385 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38386 * @return {Roo.TabPanelItem} The TabPanelItem.
38388 activate : function(id)
38390 //Roo.log('activite:' + id);
38392 var tab = this.items[id];
38396 if(tab == this.active || tab.disabled){
38400 this.fireEvent("beforetabchange", this, e, tab);
38401 if(e.cancel !== true && !tab.disabled){
38403 this.active.hide();
38405 this.active = this.items[id];
38406 this.active.show();
38407 this.fireEvent("tabchange", this, this.active);
38413 * Gets the active {@link Roo.TabPanelItem}.
38414 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38416 getActiveTab : function(){
38417 return this.active;
38421 * Updates the tab body element to fit the height of the container element
38422 * for overflow scrolling
38423 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38425 syncHeight : function(targetHeight){
38426 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38427 var bm = this.bodyEl.getMargins();
38428 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38429 this.bodyEl.setHeight(newHeight);
38433 onResize : function(){
38434 if(this.monitorResize){
38435 this.autoSizeTabs();
38440 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38442 beginUpdate : function(){
38443 this.updating = true;
38447 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38449 endUpdate : function(){
38450 this.updating = false;
38451 this.autoSizeTabs();
38455 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38457 autoSizeTabs : function()
38459 var count = this.items.length;
38460 var vcount = count - this.hiddenCount;
38463 this.stripEl.hide();
38465 this.stripEl.show();
38468 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38473 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38474 var availWidth = Math.floor(w / vcount);
38475 var b = this.stripBody;
38476 if(b.getWidth() > w){
38477 var tabs = this.items;
38478 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38479 if(availWidth < this.minTabWidth){
38480 /*if(!this.sleft){ // incomplete scrolling code
38481 this.createScrollButtons();
38484 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38487 if(this.currentTabWidth < this.preferredTabWidth){
38488 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38494 * Returns the number of tabs in this TabPanel.
38497 getCount : function(){
38498 return this.items.length;
38502 * Resizes all the tabs to the passed width
38503 * @param {Number} The new width
38505 setTabWidth : function(width){
38506 this.currentTabWidth = width;
38507 for(var i = 0, len = this.items.length; i < len; i++) {
38508 if(!this.items[i].isHidden()) {
38509 this.items[i].setWidth(width);
38515 * Destroys this TabPanel
38516 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38518 destroy : function(removeEl){
38519 Roo.EventManager.removeResizeListener(this.onResize, this);
38520 for(var i = 0, len = this.items.length; i < len; i++){
38521 this.items[i].purgeListeners();
38523 if(removeEl === true){
38524 this.el.update("");
38529 createStrip : function(container)
38531 var strip = document.createElement("nav");
38532 strip.className = Roo.bootstrap.version == 4 ?
38533 "navbar-light bg-light" :
38534 "navbar navbar-default"; //"x-tabs-wrap";
38535 container.appendChild(strip);
38539 createStripList : function(strip)
38541 // div wrapper for retard IE
38542 // returns the "tr" element.
38543 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38544 //'<div class="x-tabs-strip-wrap">'+
38545 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38546 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38547 return strip.firstChild; //.firstChild.firstChild.firstChild;
38549 createBody : function(container)
38551 var body = document.createElement("div");
38552 Roo.id(body, "tab-body");
38553 //Roo.fly(body).addClass("x-tabs-body");
38554 Roo.fly(body).addClass("tab-content");
38555 container.appendChild(body);
38558 createItemBody :function(bodyEl, id){
38559 var body = Roo.getDom(id);
38561 body = document.createElement("div");
38564 //Roo.fly(body).addClass("x-tabs-item-body");
38565 Roo.fly(body).addClass("tab-pane");
38566 bodyEl.insertBefore(body, bodyEl.firstChild);
38570 createStripElements : function(stripEl, text, closable, tpl)
38572 var td = document.createElement("li"); // was td..
38573 td.className = 'nav-item';
38575 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38578 stripEl.appendChild(td);
38580 td.className = "x-tabs-closable";
38581 if(!this.closeTpl){
38582 this.closeTpl = new Roo.Template(
38583 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38584 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38585 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38588 var el = this.closeTpl.overwrite(td, {"text": text});
38589 var close = el.getElementsByTagName("div")[0];
38590 var inner = el.getElementsByTagName("em")[0];
38591 return {"el": el, "close": close, "inner": inner};
38594 // not sure what this is..
38595 // if(!this.tabTpl){
38596 //this.tabTpl = new Roo.Template(
38597 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38598 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38600 // this.tabTpl = new Roo.Template(
38601 // '<a href="#">' +
38602 // '<span unselectable="on"' +
38603 // (this.disableTooltips ? '' : ' title="{text}"') +
38604 // ' >{text}</span></a>'
38610 var template = tpl || this.tabTpl || false;
38613 template = new Roo.Template(
38614 Roo.bootstrap.version == 4 ?
38616 '<a class="nav-link" href="#" unselectable="on"' +
38617 (this.disableTooltips ? '' : ' title="{text}"') +
38620 '<a class="nav-link" href="#">' +
38621 '<span unselectable="on"' +
38622 (this.disableTooltips ? '' : ' title="{text}"') +
38623 ' >{text}</span></a>'
38628 switch (typeof(template)) {
38632 template = new Roo.Template(template);
38638 var el = template.overwrite(td, {"text": text});
38640 var inner = el.getElementsByTagName("span")[0];
38642 return {"el": el, "inner": inner};
38650 * @class Roo.TabPanelItem
38651 * @extends Roo.util.Observable
38652 * Represents an individual item (tab plus body) in a TabPanel.
38653 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38654 * @param {String} id The id of this TabPanelItem
38655 * @param {String} text The text for the tab of this TabPanelItem
38656 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38658 Roo.bootstrap.panel.TabItem = function(config){
38660 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38661 * @type Roo.TabPanel
38663 this.tabPanel = config.panel;
38665 * The id for this TabPanelItem
38668 this.id = config.id;
38670 this.disabled = false;
38672 this.text = config.text;
38674 this.loaded = false;
38675 this.closable = config.closable;
38678 * The body element for this TabPanelItem.
38679 * @type Roo.Element
38681 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38682 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38683 this.bodyEl.setStyle("display", "block");
38684 this.bodyEl.setStyle("zoom", "1");
38685 //this.hideAction();
38687 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38689 this.el = Roo.get(els.el);
38690 this.inner = Roo.get(els.inner, true);
38691 this.textEl = Roo.bootstrap.version == 4 ?
38692 this.el : Roo.get(this.el.dom.firstChild, true);
38694 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38695 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38698 // this.el.on("mousedown", this.onTabMouseDown, this);
38699 this.el.on("click", this.onTabClick, this);
38701 if(config.closable){
38702 var c = Roo.get(els.close, true);
38703 c.dom.title = this.closeText;
38704 c.addClassOnOver("close-over");
38705 c.on("click", this.closeClick, this);
38711 * Fires when this tab becomes the active tab.
38712 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38713 * @param {Roo.TabPanelItem} this
38717 * @event beforeclose
38718 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38719 * @param {Roo.TabPanelItem} this
38720 * @param {Object} e Set cancel to true on this object to cancel the close.
38722 "beforeclose": true,
38725 * Fires when this tab is closed.
38726 * @param {Roo.TabPanelItem} this
38730 * @event deactivate
38731 * Fires when this tab is no longer the active tab.
38732 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38733 * @param {Roo.TabPanelItem} this
38735 "deactivate" : true
38737 this.hidden = false;
38739 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38742 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38744 purgeListeners : function(){
38745 Roo.util.Observable.prototype.purgeListeners.call(this);
38746 this.el.removeAllListeners();
38749 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38752 this.status_node.addClass("active");
38755 this.tabPanel.stripWrap.repaint();
38757 this.fireEvent("activate", this.tabPanel, this);
38761 * Returns true if this tab is the active tab.
38762 * @return {Boolean}
38764 isActive : function(){
38765 return this.tabPanel.getActiveTab() == this;
38769 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38772 this.status_node.removeClass("active");
38774 this.fireEvent("deactivate", this.tabPanel, this);
38777 hideAction : function(){
38778 this.bodyEl.hide();
38779 this.bodyEl.setStyle("position", "absolute");
38780 this.bodyEl.setLeft("-20000px");
38781 this.bodyEl.setTop("-20000px");
38784 showAction : function(){
38785 this.bodyEl.setStyle("position", "relative");
38786 this.bodyEl.setTop("");
38787 this.bodyEl.setLeft("");
38788 this.bodyEl.show();
38792 * Set the tooltip for the tab.
38793 * @param {String} tooltip The tab's tooltip
38795 setTooltip : function(text){
38796 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38797 this.textEl.dom.qtip = text;
38798 this.textEl.dom.removeAttribute('title');
38800 this.textEl.dom.title = text;
38804 onTabClick : function(e){
38805 e.preventDefault();
38806 this.tabPanel.activate(this.id);
38809 onTabMouseDown : function(e){
38810 e.preventDefault();
38811 this.tabPanel.activate(this.id);
38814 getWidth : function(){
38815 return this.inner.getWidth();
38818 setWidth : function(width){
38819 var iwidth = width - this.linode.getPadding("lr");
38820 this.inner.setWidth(iwidth);
38821 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38822 this.linode.setWidth(width);
38826 * Show or hide the tab
38827 * @param {Boolean} hidden True to hide or false to show.
38829 setHidden : function(hidden){
38830 this.hidden = hidden;
38831 this.linode.setStyle("display", hidden ? "none" : "");
38835 * Returns true if this tab is "hidden"
38836 * @return {Boolean}
38838 isHidden : function(){
38839 return this.hidden;
38843 * Returns the text for this tab
38846 getText : function(){
38850 autoSize : function(){
38851 //this.el.beginMeasure();
38852 this.textEl.setWidth(1);
38854 * #2804 [new] Tabs in Roojs
38855 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38857 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38858 //this.el.endMeasure();
38862 * Sets the text for the tab (Note: this also sets the tooltip text)
38863 * @param {String} text The tab's text and tooltip
38865 setText : function(text){
38867 this.textEl.update(text);
38868 this.setTooltip(text);
38869 //if(!this.tabPanel.resizeTabs){
38870 // this.autoSize();
38874 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38876 activate : function(){
38877 this.tabPanel.activate(this.id);
38881 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38883 disable : function(){
38884 if(this.tabPanel.active != this){
38885 this.disabled = true;
38886 this.status_node.addClass("disabled");
38891 * Enables this TabPanelItem if it was previously disabled.
38893 enable : function(){
38894 this.disabled = false;
38895 this.status_node.removeClass("disabled");
38899 * Sets the content for this TabPanelItem.
38900 * @param {String} content The content
38901 * @param {Boolean} loadScripts true to look for and load scripts
38903 setContent : function(content, loadScripts){
38904 this.bodyEl.update(content, loadScripts);
38908 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38909 * @return {Roo.UpdateManager} The UpdateManager
38911 getUpdateManager : function(){
38912 return this.bodyEl.getUpdateManager();
38916 * Set a URL to be used to load the content for this TabPanelItem.
38917 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38918 * @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)
38919 * @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)
38920 * @return {Roo.UpdateManager} The UpdateManager
38922 setUrl : function(url, params, loadOnce){
38923 if(this.refreshDelegate){
38924 this.un('activate', this.refreshDelegate);
38926 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38927 this.on("activate", this.refreshDelegate);
38928 return this.bodyEl.getUpdateManager();
38932 _handleRefresh : function(url, params, loadOnce){
38933 if(!loadOnce || !this.loaded){
38934 var updater = this.bodyEl.getUpdateManager();
38935 updater.update(url, params, this._setLoaded.createDelegate(this));
38940 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38941 * Will fail silently if the setUrl method has not been called.
38942 * This does not activate the panel, just updates its content.
38944 refresh : function(){
38945 if(this.refreshDelegate){
38946 this.loaded = false;
38947 this.refreshDelegate();
38952 _setLoaded : function(){
38953 this.loaded = true;
38957 closeClick : function(e){
38960 this.fireEvent("beforeclose", this, o);
38961 if(o.cancel !== true){
38962 this.tabPanel.removeTab(this.id);
38966 * The text displayed in the tooltip for the close icon.
38969 closeText : "Close this tab"
38972 * This script refer to:
38973 * Title: International Telephone Input
38974 * Author: Jack O'Connor
38975 * Code version: v12.1.12
38976 * Availability: https://github.com/jackocnr/intl-tel-input.git
38979 Roo.bootstrap.PhoneInputData = function() {
38982 "Afghanistan (افغانستان)",
38987 "Albania (Shqipëri)",
38992 "Algeria (الجزائر)",
39017 "Antigua and Barbuda",
39027 "Armenia (Հայաստան)",
39043 "Austria (Österreich)",
39048 "Azerbaijan (Azərbaycan)",
39058 "Bahrain (البحرين)",
39063 "Bangladesh (বাংলাদেশ)",
39073 "Belarus (Беларусь)",
39078 "Belgium (België)",
39108 "Bosnia and Herzegovina (Босна и Херцеговина)",
39123 "British Indian Ocean Territory",
39128 "British Virgin Islands",
39138 "Bulgaria (България)",
39148 "Burundi (Uburundi)",
39153 "Cambodia (កម្ពុជា)",
39158 "Cameroon (Cameroun)",
39167 ["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"]
39170 "Cape Verde (Kabu Verdi)",
39175 "Caribbean Netherlands",
39186 "Central African Republic (République centrafricaine)",
39206 "Christmas Island",
39212 "Cocos (Keeling) Islands",
39223 "Comoros (جزر القمر)",
39228 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39233 "Congo (Republic) (Congo-Brazzaville)",
39253 "Croatia (Hrvatska)",
39274 "Czech Republic (Česká republika)",
39279 "Denmark (Danmark)",
39294 "Dominican Republic (República Dominicana)",
39298 ["809", "829", "849"]
39316 "Equatorial Guinea (Guinea Ecuatorial)",
39336 "Falkland Islands (Islas Malvinas)",
39341 "Faroe Islands (Føroyar)",
39362 "French Guiana (Guyane française)",
39367 "French Polynesia (Polynésie française)",
39382 "Georgia (საქართველო)",
39387 "Germany (Deutschland)",
39407 "Greenland (Kalaallit Nunaat)",
39444 "Guinea-Bissau (Guiné Bissau)",
39469 "Hungary (Magyarország)",
39474 "Iceland (Ísland)",
39494 "Iraq (العراق)",
39510 "Israel (ישראל)",
39537 "Jordan (الأردن)",
39542 "Kazakhstan (Казахстан)",
39563 "Kuwait (الكويت)",
39568 "Kyrgyzstan (Кыргызстан)",
39578 "Latvia (Latvija)",
39583 "Lebanon (لبنان)",
39598 "Libya (ليبيا)",
39608 "Lithuania (Lietuva)",
39623 "Macedonia (FYROM) (Македонија)",
39628 "Madagascar (Madagasikara)",
39658 "Marshall Islands",
39668 "Mauritania (موريتانيا)",
39673 "Mauritius (Moris)",
39694 "Moldova (Republica Moldova)",
39704 "Mongolia (Монгол)",
39709 "Montenegro (Crna Gora)",
39719 "Morocco (المغرب)",
39725 "Mozambique (Moçambique)",
39730 "Myanmar (Burma) (မြန်မာ)",
39735 "Namibia (Namibië)",
39750 "Netherlands (Nederland)",
39755 "New Caledonia (Nouvelle-Calédonie)",
39790 "North Korea (조선 민주주의 인민 공화국)",
39795 "Northern Mariana Islands",
39811 "Pakistan (پاکستان)",
39821 "Palestine (فلسطين)",
39831 "Papua New Guinea",
39873 "Réunion (La Réunion)",
39879 "Romania (România)",
39895 "Saint Barthélemy",
39906 "Saint Kitts and Nevis",
39916 "Saint Martin (Saint-Martin (partie française))",
39922 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39927 "Saint Vincent and the Grenadines",
39942 "São Tomé and Príncipe (São Tomé e Príncipe)",
39947 "Saudi Arabia (المملكة العربية السعودية)",
39952 "Senegal (Sénégal)",
39982 "Slovakia (Slovensko)",
39987 "Slovenia (Slovenija)",
39997 "Somalia (Soomaaliya)",
40007 "South Korea (대한민국)",
40012 "South Sudan (جنوب السودان)",
40022 "Sri Lanka (ශ්රී ලංකාව)",
40027 "Sudan (السودان)",
40037 "Svalbard and Jan Mayen",
40048 "Sweden (Sverige)",
40053 "Switzerland (Schweiz)",
40058 "Syria (سوريا)",
40103 "Trinidad and Tobago",
40108 "Tunisia (تونس)",
40113 "Turkey (Türkiye)",
40123 "Turks and Caicos Islands",
40133 "U.S. Virgin Islands",
40143 "Ukraine (Україна)",
40148 "United Arab Emirates (الإمارات العربية المتحدة)",
40170 "Uzbekistan (Oʻzbekiston)",
40180 "Vatican City (Città del Vaticano)",
40191 "Vietnam (Việt Nam)",
40196 "Wallis and Futuna (Wallis-et-Futuna)",
40201 "Western Sahara (الصحراء الغربية)",
40207 "Yemen (اليمن)",
40231 * This script refer to:
40232 * Title: International Telephone Input
40233 * Author: Jack O'Connor
40234 * Code version: v12.1.12
40235 * Availability: https://github.com/jackocnr/intl-tel-input.git
40239 * @class Roo.bootstrap.PhoneInput
40240 * @extends Roo.bootstrap.TriggerField
40241 * An input with International dial-code selection
40243 * @cfg {String} defaultDialCode default '+852'
40244 * @cfg {Array} preferedCountries default []
40247 * Create a new PhoneInput.
40248 * @param {Object} config Configuration options
40251 Roo.bootstrap.PhoneInput = function(config) {
40252 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40255 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40257 listWidth: undefined,
40259 selectedClass: 'active',
40261 invalidClass : "has-warning",
40263 validClass: 'has-success',
40265 allowed: '0123456789',
40270 * @cfg {String} defaultDialCode The default dial code when initializing the input
40272 defaultDialCode: '+852',
40275 * @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
40277 preferedCountries: false,
40279 getAutoCreate : function()
40281 var data = Roo.bootstrap.PhoneInputData();
40282 var align = this.labelAlign || this.parentLabelAlign();
40285 this.allCountries = [];
40286 this.dialCodeMapping = [];
40288 for (var i = 0; i < data.length; i++) {
40290 this.allCountries[i] = {
40294 priority: c[3] || 0,
40295 areaCodes: c[4] || null
40297 this.dialCodeMapping[c[2]] = {
40300 priority: c[3] || 0,
40301 areaCodes: c[4] || null
40313 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40314 maxlength: this.max_length,
40315 cls : 'form-control tel-input',
40316 autocomplete: 'new-password'
40319 var hiddenInput = {
40322 cls: 'hidden-tel-input'
40326 hiddenInput.name = this.name;
40329 if (this.disabled) {
40330 input.disabled = true;
40333 var flag_container = {
40350 cls: this.hasFeedback ? 'has-feedback' : '',
40356 cls: 'dial-code-holder',
40363 cls: 'roo-select2-container input-group',
40370 if (this.fieldLabel.length) {
40373 tooltip: 'This field is required'
40379 cls: 'control-label',
40385 html: this.fieldLabel
40388 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40394 if(this.indicatorpos == 'right') {
40395 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40402 if(align == 'left') {
40410 if(this.labelWidth > 12){
40411 label.style = "width: " + this.labelWidth + 'px';
40413 if(this.labelWidth < 13 && this.labelmd == 0){
40414 this.labelmd = this.labelWidth;
40416 if(this.labellg > 0){
40417 label.cls += ' col-lg-' + this.labellg;
40418 input.cls += ' col-lg-' + (12 - this.labellg);
40420 if(this.labelmd > 0){
40421 label.cls += ' col-md-' + this.labelmd;
40422 container.cls += ' col-md-' + (12 - this.labelmd);
40424 if(this.labelsm > 0){
40425 label.cls += ' col-sm-' + this.labelsm;
40426 container.cls += ' col-sm-' + (12 - this.labelsm);
40428 if(this.labelxs > 0){
40429 label.cls += ' col-xs-' + this.labelxs;
40430 container.cls += ' col-xs-' + (12 - this.labelxs);
40440 var settings = this;
40442 ['xs','sm','md','lg'].map(function(size){
40443 if (settings[size]) {
40444 cfg.cls += ' col-' + size + '-' + settings[size];
40448 this.store = new Roo.data.Store({
40449 proxy : new Roo.data.MemoryProxy({}),
40450 reader : new Roo.data.JsonReader({
40461 'name' : 'dialCode',
40465 'name' : 'priority',
40469 'name' : 'areaCodes',
40476 if(!this.preferedCountries) {
40477 this.preferedCountries = [
40484 var p = this.preferedCountries.reverse();
40487 for (var i = 0; i < p.length; i++) {
40488 for (var j = 0; j < this.allCountries.length; j++) {
40489 if(this.allCountries[j].iso2 == p[i]) {
40490 var t = this.allCountries[j];
40491 this.allCountries.splice(j,1);
40492 this.allCountries.unshift(t);
40498 this.store.proxy.data = {
40500 data: this.allCountries
40506 initEvents : function()
40509 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40511 this.indicator = this.indicatorEl();
40512 this.flag = this.flagEl();
40513 this.dialCodeHolder = this.dialCodeHolderEl();
40515 this.trigger = this.el.select('div.flag-box',true).first();
40516 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40521 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40522 _this.list.setWidth(lw);
40525 this.list.on('mouseover', this.onViewOver, this);
40526 this.list.on('mousemove', this.onViewMove, this);
40527 this.inputEl().on("keyup", this.onKeyUp, this);
40528 this.inputEl().on("keypress", this.onKeyPress, this);
40530 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40532 this.view = new Roo.View(this.list, this.tpl, {
40533 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40536 this.view.on('click', this.onViewClick, this);
40537 this.setValue(this.defaultDialCode);
40540 onTriggerClick : function(e)
40542 Roo.log('trigger click');
40547 if(this.isExpanded()){
40549 this.hasFocus = false;
40551 this.store.load({});
40552 this.hasFocus = true;
40557 isExpanded : function()
40559 return this.list.isVisible();
40562 collapse : function()
40564 if(!this.isExpanded()){
40568 Roo.get(document).un('mousedown', this.collapseIf, this);
40569 Roo.get(document).un('mousewheel', this.collapseIf, this);
40570 this.fireEvent('collapse', this);
40574 expand : function()
40578 if(this.isExpanded() || !this.hasFocus){
40582 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40583 this.list.setWidth(lw);
40586 this.restrictHeight();
40588 Roo.get(document).on('mousedown', this.collapseIf, this);
40589 Roo.get(document).on('mousewheel', this.collapseIf, this);
40591 this.fireEvent('expand', this);
40594 restrictHeight : function()
40596 this.list.alignTo(this.inputEl(), this.listAlign);
40597 this.list.alignTo(this.inputEl(), this.listAlign);
40600 onViewOver : function(e, t)
40602 if(this.inKeyMode){
40605 var item = this.view.findItemFromChild(t);
40608 var index = this.view.indexOf(item);
40609 this.select(index, false);
40614 onViewClick : function(view, doFocus, el, e)
40616 var index = this.view.getSelectedIndexes()[0];
40618 var r = this.store.getAt(index);
40621 this.onSelect(r, index);
40623 if(doFocus !== false && !this.blockFocus){
40624 this.inputEl().focus();
40628 onViewMove : function(e, t)
40630 this.inKeyMode = false;
40633 select : function(index, scrollIntoView)
40635 this.selectedIndex = index;
40636 this.view.select(index);
40637 if(scrollIntoView !== false){
40638 var el = this.view.getNode(index);
40640 this.list.scrollChildIntoView(el, false);
40645 createList : function()
40647 this.list = Roo.get(document.body).createChild({
40649 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40650 style: 'display:none'
40653 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40656 collapseIf : function(e)
40658 var in_combo = e.within(this.el);
40659 var in_list = e.within(this.list);
40660 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40662 if (in_combo || in_list || is_list) {
40668 onSelect : function(record, index)
40670 if(this.fireEvent('beforeselect', this, record, index) !== false){
40672 this.setFlagClass(record.data.iso2);
40673 this.setDialCode(record.data.dialCode);
40674 this.hasFocus = false;
40676 this.fireEvent('select', this, record, index);
40680 flagEl : function()
40682 var flag = this.el.select('div.flag',true).first();
40689 dialCodeHolderEl : function()
40691 var d = this.el.select('input.dial-code-holder',true).first();
40698 setDialCode : function(v)
40700 this.dialCodeHolder.dom.value = '+'+v;
40703 setFlagClass : function(n)
40705 this.flag.dom.className = 'flag '+n;
40708 getValue : function()
40710 var v = this.inputEl().getValue();
40711 if(this.dialCodeHolder) {
40712 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40717 setValue : function(v)
40719 var d = this.getDialCode(v);
40721 //invalid dial code
40722 if(v.length == 0 || !d || d.length == 0) {
40724 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40725 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40731 this.setFlagClass(this.dialCodeMapping[d].iso2);
40732 this.setDialCode(d);
40733 this.inputEl().dom.value = v.replace('+'+d,'');
40734 this.hiddenEl().dom.value = this.getValue();
40739 getDialCode : function(v)
40743 if (v.length == 0) {
40744 return this.dialCodeHolder.dom.value;
40748 if (v.charAt(0) != "+") {
40751 var numericChars = "";
40752 for (var i = 1; i < v.length; i++) {
40753 var c = v.charAt(i);
40756 if (this.dialCodeMapping[numericChars]) {
40757 dialCode = v.substr(1, i);
40759 if (numericChars.length == 4) {
40769 this.setValue(this.defaultDialCode);
40773 hiddenEl : function()
40775 return this.el.select('input.hidden-tel-input',true).first();
40778 // after setting val
40779 onKeyUp : function(e){
40780 this.setValue(this.getValue());
40783 onKeyPress : function(e){
40784 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40791 * @class Roo.bootstrap.MoneyField
40792 * @extends Roo.bootstrap.ComboBox
40793 * Bootstrap MoneyField class
40796 * Create a new MoneyField.
40797 * @param {Object} config Configuration options
40800 Roo.bootstrap.MoneyField = function(config) {
40802 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40806 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40809 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40811 allowDecimals : true,
40813 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40815 decimalSeparator : ".",
40817 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40819 decimalPrecision : 0,
40821 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40823 allowNegative : true,
40825 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40829 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40831 minValue : Number.NEGATIVE_INFINITY,
40833 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40835 maxValue : Number.MAX_VALUE,
40837 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40839 minText : "The minimum value for this field is {0}",
40841 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40843 maxText : "The maximum value for this field is {0}",
40845 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40846 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40848 nanText : "{0} is not a valid number",
40850 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40854 * @cfg {String} defaults currency of the MoneyField
40855 * value should be in lkey
40857 defaultCurrency : false,
40859 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40861 thousandsDelimiter : false,
40863 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40874 getAutoCreate : function()
40876 var align = this.labelAlign || this.parentLabelAlign();
40888 cls : 'form-control roo-money-amount-input',
40889 autocomplete: 'new-password'
40892 var hiddenInput = {
40896 cls: 'hidden-number-input'
40899 if(this.max_length) {
40900 input.maxlength = this.max_length;
40904 hiddenInput.name = this.name;
40907 if (this.disabled) {
40908 input.disabled = true;
40911 var clg = 12 - this.inputlg;
40912 var cmd = 12 - this.inputmd;
40913 var csm = 12 - this.inputsm;
40914 var cxs = 12 - this.inputxs;
40918 cls : 'row roo-money-field',
40922 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40926 cls: 'roo-select2-container input-group',
40930 cls : 'form-control roo-money-currency-input',
40931 autocomplete: 'new-password',
40933 name : this.currencyName
40937 cls : 'input-group-addon',
40951 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40955 cls: this.hasFeedback ? 'has-feedback' : '',
40966 if (this.fieldLabel.length) {
40969 tooltip: 'This field is required'
40975 cls: 'control-label',
40981 html: this.fieldLabel
40984 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40990 if(this.indicatorpos == 'right') {
40991 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40998 if(align == 'left') {
41006 if(this.labelWidth > 12){
41007 label.style = "width: " + this.labelWidth + 'px';
41009 if(this.labelWidth < 13 && this.labelmd == 0){
41010 this.labelmd = this.labelWidth;
41012 if(this.labellg > 0){
41013 label.cls += ' col-lg-' + this.labellg;
41014 input.cls += ' col-lg-' + (12 - this.labellg);
41016 if(this.labelmd > 0){
41017 label.cls += ' col-md-' + this.labelmd;
41018 container.cls += ' col-md-' + (12 - this.labelmd);
41020 if(this.labelsm > 0){
41021 label.cls += ' col-sm-' + this.labelsm;
41022 container.cls += ' col-sm-' + (12 - this.labelsm);
41024 if(this.labelxs > 0){
41025 label.cls += ' col-xs-' + this.labelxs;
41026 container.cls += ' col-xs-' + (12 - this.labelxs);
41037 var settings = this;
41039 ['xs','sm','md','lg'].map(function(size){
41040 if (settings[size]) {
41041 cfg.cls += ' col-' + size + '-' + settings[size];
41048 initEvents : function()
41050 this.indicator = this.indicatorEl();
41052 this.initCurrencyEvent();
41054 this.initNumberEvent();
41057 initCurrencyEvent : function()
41060 throw "can not find store for combo";
41063 this.store = Roo.factory(this.store, Roo.data);
41064 this.store.parent = this;
41068 this.triggerEl = this.el.select('.input-group-addon', true).first();
41070 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41075 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41076 _this.list.setWidth(lw);
41079 this.list.on('mouseover', this.onViewOver, this);
41080 this.list.on('mousemove', this.onViewMove, this);
41081 this.list.on('scroll', this.onViewScroll, this);
41084 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41087 this.view = new Roo.View(this.list, this.tpl, {
41088 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41091 this.view.on('click', this.onViewClick, this);
41093 this.store.on('beforeload', this.onBeforeLoad, this);
41094 this.store.on('load', this.onLoad, this);
41095 this.store.on('loadexception', this.onLoadException, this);
41097 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41098 "up" : function(e){
41099 this.inKeyMode = true;
41103 "down" : function(e){
41104 if(!this.isExpanded()){
41105 this.onTriggerClick();
41107 this.inKeyMode = true;
41112 "enter" : function(e){
41115 if(this.fireEvent("specialkey", this, e)){
41116 this.onViewClick(false);
41122 "esc" : function(e){
41126 "tab" : function(e){
41129 if(this.fireEvent("specialkey", this, e)){
41130 this.onViewClick(false);
41138 doRelay : function(foo, bar, hname){
41139 if(hname == 'down' || this.scope.isExpanded()){
41140 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41148 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41152 initNumberEvent : function(e)
41154 this.inputEl().on("keydown" , this.fireKey, this);
41155 this.inputEl().on("focus", this.onFocus, this);
41156 this.inputEl().on("blur", this.onBlur, this);
41158 this.inputEl().relayEvent('keyup', this);
41160 if(this.indicator){
41161 this.indicator.addClass('invisible');
41164 this.originalValue = this.getValue();
41166 if(this.validationEvent == 'keyup'){
41167 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41168 this.inputEl().on('keyup', this.filterValidation, this);
41170 else if(this.validationEvent !== false){
41171 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41174 if(this.selectOnFocus){
41175 this.on("focus", this.preFocus, this);
41178 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41179 this.inputEl().on("keypress", this.filterKeys, this);
41181 this.inputEl().relayEvent('keypress', this);
41184 var allowed = "0123456789";
41186 if(this.allowDecimals){
41187 allowed += this.decimalSeparator;
41190 if(this.allowNegative){
41194 if(this.thousandsDelimiter) {
41198 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41200 var keyPress = function(e){
41202 var k = e.getKey();
41204 var c = e.getCharCode();
41207 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41208 allowed.indexOf(String.fromCharCode(c)) === -1
41214 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41218 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41223 this.inputEl().on("keypress", keyPress, this);
41227 onTriggerClick : function(e)
41234 this.loadNext = false;
41236 if(this.isExpanded()){
41241 this.hasFocus = true;
41243 if(this.triggerAction == 'all') {
41244 this.doQuery(this.allQuery, true);
41248 this.doQuery(this.getRawValue());
41251 getCurrency : function()
41253 var v = this.currencyEl().getValue();
41258 restrictHeight : function()
41260 this.list.alignTo(this.currencyEl(), this.listAlign);
41261 this.list.alignTo(this.currencyEl(), this.listAlign);
41264 onViewClick : function(view, doFocus, el, e)
41266 var index = this.view.getSelectedIndexes()[0];
41268 var r = this.store.getAt(index);
41271 this.onSelect(r, index);
41275 onSelect : function(record, index){
41277 if(this.fireEvent('beforeselect', this, record, index) !== false){
41279 this.setFromCurrencyData(index > -1 ? record.data : false);
41283 this.fireEvent('select', this, record, index);
41287 setFromCurrencyData : function(o)
41291 this.lastCurrency = o;
41293 if (this.currencyField) {
41294 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41296 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41299 this.lastSelectionText = currency;
41301 //setting default currency
41302 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41303 this.setCurrency(this.defaultCurrency);
41307 this.setCurrency(currency);
41310 setFromData : function(o)
41314 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41316 this.setFromCurrencyData(c);
41321 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41323 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41326 this.setValue(value);
41330 setCurrency : function(v)
41332 this.currencyValue = v;
41335 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41340 setValue : function(v)
41342 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41348 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41350 this.inputEl().dom.value = (v == '') ? '' :
41351 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41353 if(!this.allowZero && v === '0') {
41354 this.hiddenEl().dom.value = '';
41355 this.inputEl().dom.value = '';
41362 getRawValue : function()
41364 var v = this.inputEl().getValue();
41369 getValue : function()
41371 return this.fixPrecision(this.parseValue(this.getRawValue()));
41374 parseValue : function(value)
41376 if(this.thousandsDelimiter) {
41378 r = new RegExp(",", "g");
41379 value = value.replace(r, "");
41382 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41383 return isNaN(value) ? '' : value;
41387 fixPrecision : function(value)
41389 if(this.thousandsDelimiter) {
41391 r = new RegExp(",", "g");
41392 value = value.replace(r, "");
41395 var nan = isNaN(value);
41397 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41398 return nan ? '' : value;
41400 return parseFloat(value).toFixed(this.decimalPrecision);
41403 decimalPrecisionFcn : function(v)
41405 return Math.floor(v);
41408 validateValue : function(value)
41410 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41414 var num = this.parseValue(value);
41417 this.markInvalid(String.format(this.nanText, value));
41421 if(num < this.minValue){
41422 this.markInvalid(String.format(this.minText, this.minValue));
41426 if(num > this.maxValue){
41427 this.markInvalid(String.format(this.maxText, this.maxValue));
41434 validate : function()
41436 if(this.disabled || this.allowBlank){
41441 var currency = this.getCurrency();
41443 if(this.validateValue(this.getRawValue()) && currency.length){
41448 this.markInvalid();
41452 getName: function()
41457 beforeBlur : function()
41463 var v = this.parseValue(this.getRawValue());
41470 onBlur : function()
41474 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41475 //this.el.removeClass(this.focusClass);
41478 this.hasFocus = false;
41480 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41484 var v = this.getValue();
41486 if(String(v) !== String(this.startValue)){
41487 this.fireEvent('change', this, v, this.startValue);
41490 this.fireEvent("blur", this);
41493 inputEl : function()
41495 return this.el.select('.roo-money-amount-input', true).first();
41498 currencyEl : function()
41500 return this.el.select('.roo-money-currency-input', true).first();
41503 hiddenEl : function()
41505 return this.el.select('input.hidden-number-input',true).first();
41509 * This script refer to:
41510 * Title: Signature Pad
41512 * Availability: https://github.com/szimek/signature_pad
41516 * @class Roo.bootstrap.BezierSignature
41517 * @extends Roo.bootstrap.Component
41518 * Bootstrap BezierSignature class
41521 * Create a new BezierSignature
41522 * @param {Object} config The config object
41525 Roo.bootstrap.BezierSignature = function(config){
41526 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41532 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component, {
41538 mouse_btn_down: true,
41541 * @cfg(int) canvas height
41543 canvas_height: '200px',
41546 * @cfg(float or function) Radius of a single dot.
41551 * @cfg(float) Minimum width of a line. Defaults to 0.5.
41556 * @cfg(float) Maximum width of a line. Defaults to 2.5.
41561 * @cfg(integer) Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41566 * @cfg(integer) Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41571 * @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.
41573 bg_color: 'rgba(0, 0, 0, 0)',
41576 * @cfg(string) Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41578 dot_color: 'black',
41581 * @cfg(float) Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41583 velocity_filter_weight: 0.7,
41586 * @cfg(function) Callback when stroke begin.
41591 * @cfg(function) Callback when stroke end.
41595 getAutoCreate : function()
41597 var cls = 'roo-signature column';
41600 cls += ' ' + this.cls;
41610 for(var i = 0; i < col_sizes.length; i++) {
41611 if(this[col_sizes[i]]) {
41612 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41622 cls: 'roo-signature-body',
41626 cls: 'roo-signature-body-canvas',
41627 height: this.canvas_height,
41628 width: this.canvas_width
41635 style: 'display: none'
41643 initEvents: function()
41645 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41647 var canvas = this.canvasEl();
41649 // mouse && touch event swapping...
41650 canvas.dom.style.touchAction = 'none';
41651 canvas.dom.style.msTouchAction = 'none';
41653 this.mouse_btn_down = false;
41654 canvas.on('mousedown', this._handleMouseDown, this);
41655 canvas.on('mousemove', this._handleMouseMove, this);
41656 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41658 if (window.PointerEvent) {
41659 canvas.on('pointerdown', this._handleMouseDown, this);
41660 canvas.on('pointermove', this._handleMouseMove, this);
41661 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41664 if ('ontouchstart' in window) {
41665 canvas.on('touchstart', this._handleTouchStart, this);
41666 canvas.on('touchmove', this._handleTouchMove, this);
41667 canvas.on('touchend', this._handleTouchEnd, this);
41670 Roo.EventManager.onWindowResize(this.resize, this, true);
41672 // file input event
41673 this.fileEl().on('change', this.uploadImage, this);
41680 resize: function(){
41682 var canvas = this.canvasEl().dom;
41683 var ctx = this.canvasElCtx();
41684 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41686 // setting canvas width will clean img data
41689 var style = window.getComputedStyle ?
41690 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41692 var padding_left = parseInt(style.paddingLeft) || 0;
41693 var padding_right = parseInt(style.paddingRight) || 0;
41695 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41697 ctx.putImageData(img_data, 0, 0);
41700 _handleMouseDown: function(e)
41702 if (e.browserEvent.which === 1) {
41703 this.mouse_btn_down = true;
41704 this.strokeBegin(e);
41708 _handleMouseMove: function (e)
41710 if (this.mouse_btn_down) {
41711 this.strokeMoveUpdate(e);
41715 _handleMouseUp: function (e)
41717 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41718 this.mouse_btn_down = false;
41723 _handleTouchStart: function (e) {
41725 e.preventDefault();
41726 if (e.browserEvent.targetTouches.length === 1) {
41727 // var touch = e.browserEvent.changedTouches[0];
41728 // this.strokeBegin(touch);
41730 this.strokeBegin(e); // assume e catching the correct xy...
41734 _handleTouchMove: function (e) {
41735 e.preventDefault();
41736 // var touch = event.targetTouches[0];
41737 // _this._strokeMoveUpdate(touch);
41738 this.strokeMoveUpdate(e);
41741 _handleTouchEnd: function (e) {
41742 var wasCanvasTouched = e.target === this.canvasEl().dom;
41743 if (wasCanvasTouched) {
41744 e.preventDefault();
41745 // var touch = event.changedTouches[0];
41746 // _this._strokeEnd(touch);
41751 reset: function () {
41752 this._lastPoints = [];
41753 this._lastVelocity = 0;
41754 this._lastWidth = (this.min_width + this.max_width) / 2;
41755 this.canvasElCtx().fillStyle = this.dot_color;
41758 strokeMoveUpdate: function(e)
41760 this.strokeUpdate(e);
41762 if (this.throttle) {
41763 this.throttle(this.strokeUpdate, this.throttle);
41766 this.strokeUpdate(e);
41770 strokeBegin: function(e)
41772 var newPointGroup = {
41773 color: this.dot_color,
41777 if (typeof this.onBegin === 'function') {
41781 this.curve_data.push(newPointGroup);
41783 this.strokeUpdate(e);
41786 strokeUpdate: function(e)
41788 var rect = this.canvasEl().dom.getBoundingClientRect();
41789 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41790 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41791 var lastPoints = lastPointGroup.points;
41792 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41793 var isLastPointTooClose = lastPoint
41794 ? point.distanceTo(lastPoint) <= this.min_distance
41796 var color = lastPointGroup.color;
41797 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41798 var curve = this.addPoint(point);
41800 this.drawDot({color: color, point: point});
41803 this.drawCurve({color: color, curve: curve});
41813 strokeEnd: function(e)
41815 this.strokeUpdate(e);
41816 if (typeof this.onEnd === 'function') {
41821 addPoint: function (point) {
41822 var _lastPoints = this._lastPoints;
41823 _lastPoints.push(point);
41824 if (_lastPoints.length > 2) {
41825 if (_lastPoints.length === 3) {
41826 _lastPoints.unshift(_lastPoints[0]);
41828 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41829 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41830 _lastPoints.shift();
41836 calculateCurveWidths: function (startPoint, endPoint) {
41837 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41838 (1 - this.velocity_filter_weight) * this._lastVelocity;
41840 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41843 start: this._lastWidth
41846 this._lastVelocity = velocity;
41847 this._lastWidth = newWidth;
41851 drawDot: function (_a) {
41852 var color = _a.color, point = _a.point;
41853 var ctx = this.canvasElCtx();
41854 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41856 this.drawCurveSegment(point.x, point.y, width);
41858 ctx.fillStyle = color;
41862 drawCurve: function (_a) {
41863 var color = _a.color, curve = _a.curve;
41864 var ctx = this.canvasElCtx();
41865 var widthDelta = curve.endWidth - curve.startWidth;
41866 var drawSteps = Math.floor(curve.length()) * 2;
41868 ctx.fillStyle = color;
41869 for (var i = 0; i < drawSteps; i += 1) {
41870 var t = i / drawSteps;
41876 var x = uuu * curve.startPoint.x;
41877 x += 3 * uu * t * curve.control1.x;
41878 x += 3 * u * tt * curve.control2.x;
41879 x += ttt * curve.endPoint.x;
41880 var y = uuu * curve.startPoint.y;
41881 y += 3 * uu * t * curve.control1.y;
41882 y += 3 * u * tt * curve.control2.y;
41883 y += ttt * curve.endPoint.y;
41884 var width = curve.startWidth + ttt * widthDelta;
41885 this.drawCurveSegment(x, y, width);
41891 drawCurveSegment: function (x, y, width) {
41892 var ctx = this.canvasElCtx();
41894 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
41895 this.is_empty = false;
41900 var ctx = this.canvasElCtx();
41901 var canvas = this.canvasEl().dom;
41902 ctx.fillStyle = this.bg_color;
41903 ctx.clearRect(0, 0, canvas.width, canvas.height);
41904 ctx.fillRect(0, 0, canvas.width, canvas.height);
41905 this.curve_data = [];
41907 this.is_empty = true;
41912 return this.el.select('input',true).first();
41915 canvasEl: function()
41917 return this.el.select('canvas',true).first();
41920 canvasElCtx: function()
41922 return this.el.select('canvas',true).first().dom.getContext('2d');
41925 getImage: function(type)
41927 if(this.is_empty) {
41932 return this.canvasEl().dom.toDataURL('image/'+type, 1);
41935 drawFromImage: function(img_src)
41937 var img = new Image();
41939 img.onload = function(){
41940 this.canvasElCtx().drawImage(img, 0, 0);
41945 this.is_empty = false;
41948 selectImage: function()
41950 this.fileEl().dom.click();
41953 uploadImage: function(e)
41955 var reader = new FileReader();
41957 reader.onload = function(e){
41958 var img = new Image();
41959 img.onload = function(){
41961 this.canvasElCtx().drawImage(img, 0, 0);
41963 img.src = e.target.result;
41966 reader.readAsDataURL(e.target.files[0]);
41969 // Bezier Point Constructor
41970 Point: (function () {
41971 function Point(x, y, time) {
41974 this.time = time || Date.now();
41976 Point.prototype.distanceTo = function (start) {
41977 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
41979 Point.prototype.equals = function (other) {
41980 return this.x === other.x && this.y === other.y && this.time === other.time;
41982 Point.prototype.velocityFrom = function (start) {
41983 return this.time !== start.time
41984 ? this.distanceTo(start) / (this.time - start.time)
41991 // Bezier Constructor
41992 Bezier: (function () {
41993 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
41994 this.startPoint = startPoint;
41995 this.control2 = control2;
41996 this.control1 = control1;
41997 this.endPoint = endPoint;
41998 this.startWidth = startWidth;
41999 this.endWidth = endWidth;
42001 Bezier.fromPoints = function (points, widths, scope) {
42002 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
42003 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
42004 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42006 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42007 var dx1 = s1.x - s2.x;
42008 var dy1 = s1.y - s2.y;
42009 var dx2 = s2.x - s3.x;
42010 var dy2 = s2.y - s3.y;
42011 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42012 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42013 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42014 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42015 var dxm = m1.x - m2.x;
42016 var dym = m1.y - m2.y;
42017 var k = l2 / (l1 + l2);
42018 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42019 var tx = s2.x - cm.x;
42020 var ty = s2.y - cm.y;
42022 c1: new scope.Point(m1.x + tx, m1.y + ty),
42023 c2: new scope.Point(m2.x + tx, m2.y + ty)
42026 Bezier.prototype.length = function () {
42031 for (var i = 0; i <= steps; i += 1) {
42033 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42034 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42036 var xdiff = cx - px;
42037 var ydiff = cy - py;
42038 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42045 Bezier.prototype.point = function (t, start, c1, c2, end) {
42046 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42047 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42048 + (3.0 * c2 * (1.0 - t) * t * t)
42049 + (end * t * t * t);
42054 throttle: function(fn, wait) {
42055 if (wait === void 0) { wait = 250; }
42057 var timeout = null;
42061 var later = function () {
42062 previous = Date.now();
42064 result = fn.apply(storedContext, storedArgs);
42066 storedContext = null;
42070 return function wrapper() {
42072 for (var _i = 0; _i < arguments.length; _i++) {
42073 args[_i] = arguments[_i];
42075 var now = Date.now();
42076 var remaining = wait - (now - previous);
42077 storedContext = this;
42079 if (remaining <= 0 || remaining > wait) {
42081 clearTimeout(timeout);
42085 result = fn.apply(storedContext, storedArgs);
42087 storedContext = null;
42091 else if (!timeout) {
42092 timeout = window.setTimeout(later, remaining);