2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets[0], function(s) {
10 if (s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 addxtype : function(tree,cntr)
179 cn = Roo.factory(tree);
180 //Roo.log(['addxtype', cn]);
182 cn.parentType = this.xtype; //??
183 cn.parentId = this.id;
185 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 if (typeof(cn.container_method) == 'string') {
187 cntr = cn.container_method;
191 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
193 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
195 var build_from_html = Roo.XComponent.build_from_html;
197 var is_body = (tree.xtype == 'Body') ;
199 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
201 var self_cntr_el = Roo.get(this[cntr](false));
203 // do not try and build conditional elements
204 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
208 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
209 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
210 return this.addxtypeChild(tree,cntr, is_body);
213 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
216 return this.addxtypeChild(Roo.apply({}, tree),cntr);
219 Roo.log('skipping render');
225 if (!build_from_html) {
229 // this i think handles overlaying multiple children of the same type
230 // with the sam eelement.. - which might be buggy..
232 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
238 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
242 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
249 addxtypeChild : function (tree, cntr, is_body)
251 Roo.debug && Roo.log('addxtypeChild:' + cntr);
253 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
256 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
257 (typeof(tree['flexy:foreach']) != 'undefined');
261 skip_children = false;
262 // render the element if it's not BODY.
265 // if parent was disabled, then do not try and create the children..
266 if(!this[cntr](true)){
271 cn = Roo.factory(tree);
273 cn.parentType = this.xtype; //??
274 cn.parentId = this.id;
276 var build_from_html = Roo.XComponent.build_from_html;
279 // does the container contain child eleemnts with 'xtype' attributes.
280 // that match this xtype..
281 // note - when we render we create these as well..
282 // so we should check to see if body has xtype set.
283 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
285 var self_cntr_el = Roo.get(this[cntr](false));
286 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
288 //Roo.log(Roo.XComponent.build_from_html);
289 //Roo.log("got echild:");
292 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
293 // and are not displayed -this causes this to use up the wrong element when matching.
294 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
297 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
298 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
304 //echild.dom.removeAttribute('xtype');
306 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
307 Roo.debug && Roo.log(self_cntr_el);
308 Roo.debug && Roo.log(echild);
309 Roo.debug && Roo.log(cn);
315 // if object has flexy:if - then it may or may not be rendered.
316 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
317 // skip a flexy if element.
318 Roo.debug && Roo.log('skipping render');
319 Roo.debug && Roo.log(tree);
321 Roo.debug && Roo.log('skipping all children');
322 skip_children = true;
327 // actually if flexy:foreach is found, we really want to create
328 // multiple copies here...
330 //Roo.log(this[cntr]());
331 // some elements do not have render methods.. like the layouts...
333 if(this[cntr](true) === false){
338 cn.render && cn.render(this[cntr](true));
341 // then add the element..
348 if (typeof (tree.menu) != 'undefined') {
349 tree.menu.parentType = cn.xtype;
350 tree.menu.triggerEl = cn.el;
351 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
355 if (!tree.items || !tree.items.length) {
357 //Roo.log(["no children", this]);
362 var items = tree.items;
365 //Roo.log(items.length);
367 if (!skip_children) {
368 for(var i =0;i < items.length;i++) {
369 // Roo.log(['add child', items[i]]);
370 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
376 //Roo.log("fire childrenrendered");
378 cn.fireEvent('childrenrendered', this);
384 * Set the element that will be used to show or hide
386 setVisibilityEl : function(el)
388 this.visibilityEl = el;
392 * Get the element that will be used to show or hide
394 getVisibilityEl : function()
396 if (typeof(this.visibilityEl) == 'object') {
397 return this.visibilityEl;
400 if (typeof(this.visibilityEl) == 'string') {
401 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
408 * Show a component - removes 'hidden' class
412 if(!this.getVisibilityEl()){
416 this.getVisibilityEl().removeClass(['hidden','d-none']);
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass(['hidden','d-none']);
433 this.fireEvent('hide', this);
446 * @class Roo.bootstrap.Body
447 * @extends Roo.bootstrap.Component
448 * Bootstrap Body class
452 * @param {Object} config The config object
455 Roo.bootstrap.Body = function(config){
457 config = config || {};
459 Roo.bootstrap.Body.superclass.constructor.call(this, config);
460 this.el = Roo.get(config.el ? config.el : document.body );
461 if (this.cls && this.cls.length) {
462 Roo.get(document.body).addClass(this.cls);
466 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
468 is_body : true,// just to make sure it's constructed?
473 onRender : function(ct, position)
475 /* Roo.log("Roo.bootstrap.Body - onRender");
476 if (this.cls && this.cls.length) {
477 Roo.get(document.body).addClass(this.cls);
496 * @class Roo.bootstrap.ButtonGroup
497 * @extends Roo.bootstrap.Component
498 * Bootstrap ButtonGroup class
499 * @cfg {String} size lg | sm | xs (default empty normal)
500 * @cfg {String} align vertical | justified (default none)
501 * @cfg {String} direction up | down (default down)
502 * @cfg {Boolean} toolbar false | true
503 * @cfg {Boolean} btn true | false
508 * @param {Object} config The config object
511 Roo.bootstrap.ButtonGroup = function(config){
512 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
515 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
523 getAutoCreate : function(){
529 cfg.html = this.html || cfg.html;
540 if (['vertical','justified'].indexOf(this.align)!==-1) {
541 cfg.cls = 'btn-group-' + this.align;
543 if (this.align == 'justified') {
544 console.log(this.items);
548 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
549 cfg.cls += ' btn-group-' + this.size;
552 if (this.direction == 'up') {
553 cfg.cls += ' dropup' ;
559 * Add a button to the group (similar to NavItem API.)
561 addItem : function(cfg)
563 var cn = new Roo.bootstrap.Button(cfg);
565 cn.parentId = this.id;
566 cn.onRender(this.el, null);
580 * @class Roo.bootstrap.Button
581 * @extends Roo.bootstrap.Component
582 * Bootstrap Button class
583 * @cfg {String} html The button content
584 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
585 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
586 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
587 * @cfg {String} size ( lg | sm | xs)
588 * @cfg {String} tag ( a | input | submit)
589 * @cfg {String} href empty or href
590 * @cfg {Boolean} disabled default false;
591 * @cfg {Boolean} isClose default false;
592 * @cfg {String} glyphicon depricated - use fa
593 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
594 * @cfg {String} badge text for badge
595 * @cfg {String} theme (default|glow)
596 * @cfg {Boolean} inverse dark themed version
597 * @cfg {Boolean} toggle is it a slidy toggle button
598 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
599 * @cfg {String} ontext text for on slidy toggle state
600 * @cfg {String} offtext text for off slidy toggle state
601 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
602 * @cfg {Boolean} removeClass remove the standard class..
603 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
606 * Create a new button
607 * @param {Object} config The config object
611 Roo.bootstrap.Button = function(config){
612 Roo.bootstrap.Button.superclass.constructor.call(this, config);
613 this.weightClass = ["btn-default btn-outline-secondary",
625 * When a butotn is pressed
626 * @param {Roo.bootstrap.Button} btn
627 * @param {Roo.EventObject} e
632 * After the button has been toggles
633 * @param {Roo.bootstrap.Button} btn
634 * @param {Roo.EventObject} e
635 * @param {boolean} pressed (also available as button.pressed)
641 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
662 preventDefault: true,
670 getAutoCreate : function(){
678 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
679 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
684 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
686 if (this.toggle == true) {
689 cls: 'slider-frame roo-button',
694 'data-off-text':'OFF',
695 cls: 'slider-button',
701 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
702 cfg.cls += ' '+this.weight;
711 cfg["aria-hidden"] = true;
713 cfg.html = "×";
719 if (this.theme==='default') {
720 cfg.cls = 'btn roo-button';
722 //if (this.parentType != 'Navbar') {
723 this.weight = this.weight.length ? this.weight : 'default';
725 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
727 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
728 var weight = this.weight == 'default' ? 'secondary' : this.weight;
729 cfg.cls += ' btn-' + outline + weight;
730 if (this.weight == 'default') {
732 cfg.cls += ' btn-' + this.weight;
735 } else if (this.theme==='glow') {
738 cfg.cls = 'btn-glow roo-button';
740 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
742 cfg.cls += ' ' + this.weight;
748 this.cls += ' inverse';
752 if (this.active || this.pressed === true) {
753 cfg.cls += ' active';
757 cfg.disabled = 'disabled';
761 Roo.log('changing to ul' );
763 this.glyphicon = 'caret';
764 if (Roo.bootstrap.version == 4) {
765 this.fa = 'caret-down';
770 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
772 //gsRoo.log(this.parentType);
773 if (this.parentType === 'Navbar' && !this.parent().bar) {
774 Roo.log('changing to li?');
783 href : this.href || '#'
786 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
787 cfg.cls += ' dropdown';
794 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
796 if (this.glyphicon) {
797 cfg.html = ' ' + cfg.html;
802 cls: 'glyphicon glyphicon-' + this.glyphicon
807 cfg.html = ' ' + cfg.html;
812 cls: 'fa fas fa-' + this.fa
822 // cfg.cls='btn roo-button';
826 var value = cfg.html;
831 cls: 'glyphicon glyphicon-' + this.glyphicon,
838 cls: 'fa fas fa-' + this.fa,
843 var bw = this.badge_weight.length ? this.badge_weight :
844 (this.weight.length ? this.weight : 'secondary');
845 bw = bw == 'default' ? 'secondary' : bw;
851 cls: 'badge badge-' + bw,
860 cfg.cls += ' dropdown';
861 cfg.html = typeof(cfg.html) != 'undefined' ?
862 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
865 if (cfg.tag !== 'a' && this.href !== '') {
866 throw "Tag must be a to set href.";
867 } else if (this.href.length > 0) {
868 cfg.href = this.href;
871 if(this.removeClass){
876 cfg.target = this.target;
881 initEvents: function() {
882 // Roo.log('init events?');
883 // Roo.log(this.el.dom);
886 if (typeof (this.menu) != 'undefined') {
887 this.menu.parentType = this.xtype;
888 this.menu.triggerEl = this.el;
889 this.addxtype(Roo.apply({}, this.menu));
893 if (this.el.hasClass('roo-button')) {
894 this.el.on('click', this.onClick, this);
896 this.el.select('.roo-button').on('click', this.onClick, this);
899 if(this.removeClass){
900 this.el.on('click', this.onClick, this);
903 this.el.enableDisplayMode();
906 onClick : function(e)
912 Roo.log('button on click ');
913 if(this.preventDefault){
917 if (this.pressed === true || this.pressed === false) {
918 this.toggleActive(e);
922 this.fireEvent('click', this, e);
926 * Enables this button
930 this.disabled = false;
931 this.el.removeClass('disabled');
935 * Disable this button
939 this.disabled = true;
940 this.el.addClass('disabled');
943 * sets the active state on/off,
944 * @param {Boolean} state (optional) Force a particular state
946 setActive : function(v) {
948 this.el[v ? 'addClass' : 'removeClass']('active');
952 * toggles the current active state
954 toggleActive : function(e)
956 this.setActive(!this.pressed);
957 this.fireEvent('toggle', this, e, !this.pressed);
960 * get the current active state
961 * @return {boolean} true if it's active
963 isActive : function()
965 return this.el.hasClass('active');
968 * set the text of the first selected button
970 setText : function(str)
972 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
975 * get the text of the first selected button
979 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
982 setWeight : function(str)
984 this.el.removeClass(this.weightClass);
986 var outline = this.outline ? 'outline-' : '';
987 if (str == 'default') {
988 this.el.addClass('btn-default btn-outline-secondary');
991 this.el.addClass('btn-' + outline + str);
1005 * @class Roo.bootstrap.Column
1006 * @extends Roo.bootstrap.Component
1007 * Bootstrap Column class
1008 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1009 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1010 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1011 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1012 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1013 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1014 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1015 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1018 * @cfg {Boolean} hidden (true|false) hide the element
1019 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1020 * @cfg {String} fa (ban|check|...) font awesome icon
1021 * @cfg {Number} fasize (1|2|....) font awsome size
1023 * @cfg {String} icon (info-sign|check|...) glyphicon name
1025 * @cfg {String} html content of column.
1028 * Create a new Column
1029 * @param {Object} config The config object
1032 Roo.bootstrap.Column = function(config){
1033 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1036 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1054 getAutoCreate : function(){
1055 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1063 ['xs','sm','md','lg'].map(function(size){
1064 //Roo.log( size + ':' + settings[size]);
1066 if (settings[size+'off'] !== false) {
1067 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1070 if (settings[size] === false) {
1074 if (!settings[size]) { // 0 = hidden
1075 cfg.cls += ' hidden-' + size;
1078 cfg.cls += ' col-' + size + '-' + settings[size];
1083 cfg.cls += ' hidden';
1086 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1087 cfg.cls +=' alert alert-' + this.alert;
1091 if (this.html.length) {
1092 cfg.html = this.html;
1096 if (this.fasize > 1) {
1097 fasize = ' fa-' + this.fasize + 'x';
1099 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1104 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1123 * @class Roo.bootstrap.Container
1124 * @extends Roo.bootstrap.Component
1125 * Bootstrap Container class
1126 * @cfg {Boolean} jumbotron is it a jumbotron element
1127 * @cfg {String} html content of element
1128 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1129 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1130 * @cfg {String} header content of header (for panel)
1131 * @cfg {String} footer content of footer (for panel)
1132 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1133 * @cfg {String} tag (header|aside|section) type of HTML tag.
1134 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1135 * @cfg {String} fa font awesome icon
1136 * @cfg {String} icon (info-sign|check|...) glyphicon name
1137 * @cfg {Boolean} hidden (true|false) hide the element
1138 * @cfg {Boolean} expandable (true|false) default false
1139 * @cfg {Boolean} expanded (true|false) default true
1140 * @cfg {String} rheader contet on the right of header
1141 * @cfg {Boolean} clickable (true|false) default false
1145 * Create a new Container
1146 * @param {Object} config The config object
1149 Roo.bootstrap.Container = function(config){
1150 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1156 * After the panel has been expand
1158 * @param {Roo.bootstrap.Container} this
1163 * After the panel has been collapsed
1165 * @param {Roo.bootstrap.Container} this
1170 * When a element is chick
1171 * @param {Roo.bootstrap.Container} this
1172 * @param {Roo.EventObject} e
1178 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1196 getChildContainer : function() {
1202 if (this.panel.length) {
1203 return this.el.select('.panel-body',true).first();
1210 getAutoCreate : function(){
1213 tag : this.tag || 'div',
1217 if (this.jumbotron) {
1218 cfg.cls = 'jumbotron';
1223 // - this is applied by the parent..
1225 // cfg.cls = this.cls + '';
1228 if (this.sticky.length) {
1230 var bd = Roo.get(document.body);
1231 if (!bd.hasClass('bootstrap-sticky')) {
1232 bd.addClass('bootstrap-sticky');
1233 Roo.select('html',true).setStyle('height', '100%');
1236 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1240 if (this.well.length) {
1241 switch (this.well) {
1244 cfg.cls +=' well well-' +this.well;
1253 cfg.cls += ' hidden';
1257 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1258 cfg.cls +=' alert alert-' + this.alert;
1263 if (this.panel.length) {
1264 cfg.cls += ' panel panel-' + this.panel;
1266 if (this.header.length) {
1270 if(this.expandable){
1272 cfg.cls = cfg.cls + ' expandable';
1276 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1284 cls : 'panel-title',
1285 html : (this.expandable ? ' ' : '') + this.header
1289 cls: 'panel-header-right',
1295 cls : 'panel-heading',
1296 style : this.expandable ? 'cursor: pointer' : '',
1304 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1309 if (this.footer.length) {
1311 cls : 'panel-footer',
1320 body.html = this.html || cfg.html;
1321 // prefix with the icons..
1323 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1326 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1331 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1332 cfg.cls = 'container';
1338 initEvents: function()
1340 if(this.expandable){
1341 var headerEl = this.headerEl();
1344 headerEl.on('click', this.onToggleClick, this);
1349 this.el.on('click', this.onClick, this);
1354 onToggleClick : function()
1356 var headerEl = this.headerEl();
1372 if(this.fireEvent('expand', this)) {
1374 this.expanded = true;
1376 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1378 this.el.select('.panel-body',true).first().removeClass('hide');
1380 var toggleEl = this.toggleEl();
1386 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1391 collapse : function()
1393 if(this.fireEvent('collapse', this)) {
1395 this.expanded = false;
1397 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1398 this.el.select('.panel-body',true).first().addClass('hide');
1400 var toggleEl = this.toggleEl();
1406 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1410 toggleEl : function()
1412 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1416 return this.el.select('.panel-heading .fa',true).first();
1419 headerEl : function()
1421 if(!this.el || !this.panel.length || !this.header.length){
1425 return this.el.select('.panel-heading',true).first()
1430 if(!this.el || !this.panel.length){
1434 return this.el.select('.panel-body',true).first()
1437 titleEl : function()
1439 if(!this.el || !this.panel.length || !this.header.length){
1443 return this.el.select('.panel-title',true).first();
1446 setTitle : function(v)
1448 var titleEl = this.titleEl();
1454 titleEl.dom.innerHTML = v;
1457 getTitle : function()
1460 var titleEl = this.titleEl();
1466 return titleEl.dom.innerHTML;
1469 setRightTitle : function(v)
1471 var t = this.el.select('.panel-header-right',true).first();
1477 t.dom.innerHTML = v;
1480 onClick : function(e)
1484 this.fireEvent('click', this, e);
1497 * @class Roo.bootstrap.Img
1498 * @extends Roo.bootstrap.Component
1499 * Bootstrap Img class
1500 * @cfg {Boolean} imgResponsive false | true
1501 * @cfg {String} border rounded | circle | thumbnail
1502 * @cfg {String} src image source
1503 * @cfg {String} alt image alternative text
1504 * @cfg {String} href a tag href
1505 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1506 * @cfg {String} xsUrl xs image source
1507 * @cfg {String} smUrl sm image source
1508 * @cfg {String} mdUrl md image source
1509 * @cfg {String} lgUrl lg image source
1512 * Create a new Input
1513 * @param {Object} config The config object
1516 Roo.bootstrap.Img = function(config){
1517 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1523 * The img click event for the img.
1524 * @param {Roo.EventObject} e
1530 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1532 imgResponsive: true,
1542 getAutoCreate : function()
1544 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1545 return this.createSingleImg();
1550 cls: 'roo-image-responsive-group',
1555 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1557 if(!_this[size + 'Url']){
1563 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1564 html: _this.html || cfg.html,
1565 src: _this[size + 'Url']
1568 img.cls += ' roo-image-responsive-' + size;
1570 var s = ['xs', 'sm', 'md', 'lg'];
1572 s.splice(s.indexOf(size), 1);
1574 Roo.each(s, function(ss){
1575 img.cls += ' hidden-' + ss;
1578 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1579 cfg.cls += ' img-' + _this.border;
1583 cfg.alt = _this.alt;
1596 a.target = _this.target;
1600 cfg.cn.push((_this.href) ? a : img);
1607 createSingleImg : function()
1611 cls: (this.imgResponsive) ? 'img-responsive' : '',
1613 src : 'about:blank' // just incase src get's set to undefined?!?
1616 cfg.html = this.html || cfg.html;
1618 cfg.src = this.src || cfg.src;
1620 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1621 cfg.cls += ' img-' + this.border;
1638 a.target = this.target;
1643 return (this.href) ? a : cfg;
1646 initEvents: function()
1649 this.el.on('click', this.onClick, this);
1654 onClick : function(e)
1656 Roo.log('img onclick');
1657 this.fireEvent('click', this, e);
1660 * Sets the url of the image - used to update it
1661 * @param {String} url the url of the image
1664 setSrc : function(url)
1668 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1669 this.el.dom.src = url;
1673 this.el.select('img', true).first().dom.src = url;
1689 * @class Roo.bootstrap.Link
1690 * @extends Roo.bootstrap.Component
1691 * Bootstrap Link Class
1692 * @cfg {String} alt image alternative text
1693 * @cfg {String} href a tag href
1694 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1695 * @cfg {String} html the content of the link.
1696 * @cfg {String} anchor name for the anchor link
1697 * @cfg {String} fa - favicon
1699 * @cfg {Boolean} preventDefault (true | false) default false
1703 * Create a new Input
1704 * @param {Object} config The config object
1707 Roo.bootstrap.Link = function(config){
1708 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1714 * The img click event for the img.
1715 * @param {Roo.EventObject} e
1721 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1725 preventDefault: false,
1731 getAutoCreate : function()
1733 var html = this.html || '';
1735 if (this.fa !== false) {
1736 html = '<i class="fa fa-' + this.fa + '"></i>';
1741 // anchor's do not require html/href...
1742 if (this.anchor === false) {
1744 cfg.href = this.href || '#';
1746 cfg.name = this.anchor;
1747 if (this.html !== false || this.fa !== false) {
1750 if (this.href !== false) {
1751 cfg.href = this.href;
1755 if(this.alt !== false){
1760 if(this.target !== false) {
1761 cfg.target = this.target;
1767 initEvents: function() {
1769 if(!this.href || this.preventDefault){
1770 this.el.on('click', this.onClick, this);
1774 onClick : function(e)
1776 if(this.preventDefault){
1779 //Roo.log('img onclick');
1780 this.fireEvent('click', this, e);
1793 * @class Roo.bootstrap.Header
1794 * @extends Roo.bootstrap.Component
1795 * Bootstrap Header class
1796 * @cfg {String} html content of header
1797 * @cfg {Number} level (1|2|3|4|5|6) default 1
1800 * Create a new Header
1801 * @param {Object} config The config object
1805 Roo.bootstrap.Header = function(config){
1806 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1809 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1817 getAutoCreate : function(){
1822 tag: 'h' + (1 *this.level),
1823 html: this.html || ''
1835 * Ext JS Library 1.1.1
1836 * Copyright(c) 2006-2007, Ext JS, LLC.
1838 * Originally Released Under LGPL - original licence link has changed is not relivant.
1841 * <script type="text/javascript">
1845 * @class Roo.bootstrap.MenuMgr
1846 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1849 Roo.bootstrap.MenuMgr = function(){
1850 var menus, active, groups = {}, attached = false, lastShow = new Date();
1852 // private - called when first menu is created
1855 active = new Roo.util.MixedCollection();
1856 Roo.get(document).addKeyListener(27, function(){
1857 if(active.length > 0){
1865 if(active && active.length > 0){
1866 var c = active.clone();
1876 if(active.length < 1){
1877 Roo.get(document).un("mouseup", onMouseDown);
1885 var last = active.last();
1886 lastShow = new Date();
1889 Roo.get(document).on("mouseup", onMouseDown);
1894 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1895 m.parentMenu.activeChild = m;
1896 }else if(last && last.isVisible()){
1897 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1902 function onBeforeHide(m){
1904 m.activeChild.hide();
1906 if(m.autoHideTimer){
1907 clearTimeout(m.autoHideTimer);
1908 delete m.autoHideTimer;
1913 function onBeforeShow(m){
1914 var pm = m.parentMenu;
1915 if(!pm && !m.allowOtherMenus){
1917 }else if(pm && pm.activeChild && active != m){
1918 pm.activeChild.hide();
1922 // private this should really trigger on mouseup..
1923 function onMouseDown(e){
1924 Roo.log("on Mouse Up");
1926 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1927 Roo.log("MenuManager hideAll");
1936 function onBeforeCheck(mi, state){
1938 var g = groups[mi.group];
1939 for(var i = 0, l = g.length; i < l; i++){
1941 g[i].setChecked(false);
1950 * Hides all menus that are currently visible
1952 hideAll : function(){
1957 register : function(menu){
1961 menus[menu.id] = menu;
1962 menu.on("beforehide", onBeforeHide);
1963 menu.on("hide", onHide);
1964 menu.on("beforeshow", onBeforeShow);
1965 menu.on("show", onShow);
1967 if(g && menu.events["checkchange"]){
1971 groups[g].push(menu);
1972 menu.on("checkchange", onCheck);
1977 * Returns a {@link Roo.menu.Menu} object
1978 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1979 * be used to generate and return a new Menu instance.
1981 get : function(menu){
1982 if(typeof menu == "string"){ // menu id
1984 }else if(menu.events){ // menu instance
1987 /*else if(typeof menu.length == 'number'){ // array of menu items?
1988 return new Roo.bootstrap.Menu({items:menu});
1989 }else{ // otherwise, must be a config
1990 return new Roo.bootstrap.Menu(menu);
1997 unregister : function(menu){
1998 delete menus[menu.id];
1999 menu.un("beforehide", onBeforeHide);
2000 menu.un("hide", onHide);
2001 menu.un("beforeshow", onBeforeShow);
2002 menu.un("show", onShow);
2004 if(g && menu.events["checkchange"]){
2005 groups[g].remove(menu);
2006 menu.un("checkchange", onCheck);
2011 registerCheckable : function(menuItem){
2012 var g = menuItem.group;
2017 groups[g].push(menuItem);
2018 menuItem.on("beforecheckchange", onBeforeCheck);
2023 unregisterCheckable : function(menuItem){
2024 var g = menuItem.group;
2026 groups[g].remove(menuItem);
2027 menuItem.un("beforecheckchange", onBeforeCheck);
2039 * @class Roo.bootstrap.Menu
2040 * @extends Roo.bootstrap.Component
2041 * Bootstrap Menu class - container for MenuItems
2042 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2043 * @cfg {bool} hidden if the menu should be hidden when rendered.
2044 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2045 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2049 * @param {Object} config The config object
2053 Roo.bootstrap.Menu = function(config){
2054 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2055 if (this.registerMenu && this.type != 'treeview') {
2056 Roo.bootstrap.MenuMgr.register(this);
2063 * Fires before this menu is displayed
2064 * @param {Roo.menu.Menu} this
2069 * Fires before this menu is hidden
2070 * @param {Roo.menu.Menu} this
2075 * Fires after this menu is displayed
2076 * @param {Roo.menu.Menu} this
2081 * Fires after this menu is hidden
2082 * @param {Roo.menu.Menu} this
2087 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2088 * @param {Roo.menu.Menu} this
2089 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2090 * @param {Roo.EventObject} e
2095 * Fires when the mouse is hovering over this menu
2096 * @param {Roo.menu.Menu} this
2097 * @param {Roo.EventObject} e
2098 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2103 * Fires when the mouse exits this menu
2104 * @param {Roo.menu.Menu} this
2105 * @param {Roo.EventObject} e
2106 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2111 * Fires when a menu item contained in this menu is clicked
2112 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2113 * @param {Roo.EventObject} e
2117 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2120 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2124 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2127 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2129 registerMenu : true,
2131 menuItems :false, // stores the menu items..
2141 getChildContainer : function() {
2145 getAutoCreate : function(){
2147 //if (['right'].indexOf(this.align)!==-1) {
2148 // cfg.cn[1].cls += ' pull-right'
2154 cls : 'dropdown-menu' ,
2155 style : 'z-index:1000'
2159 if (this.type === 'submenu') {
2160 cfg.cls = 'submenu active';
2162 if (this.type === 'treeview') {
2163 cfg.cls = 'treeview-menu';
2168 initEvents : function() {
2170 // Roo.log("ADD event");
2171 // Roo.log(this.triggerEl.dom);
2173 this.triggerEl.on('click', this.onTriggerClick, this);
2175 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2178 if (this.triggerEl.hasClass('nav-item')) {
2179 // dropdown toggle on the 'a' in BS4?
2180 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2182 this.triggerEl.addClass('dropdown-toggle');
2185 this.el.on('touchstart' , this.onTouch, this);
2187 this.el.on('click' , this.onClick, this);
2189 this.el.on("mouseover", this.onMouseOver, this);
2190 this.el.on("mouseout", this.onMouseOut, this);
2194 findTargetItem : function(e)
2196 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2200 //Roo.log(t); Roo.log(t.id);
2202 //Roo.log(this.menuitems);
2203 return this.menuitems.get(t.id);
2205 //return this.items.get(t.menuItemId);
2211 onTouch : function(e)
2213 Roo.log("menu.onTouch");
2214 //e.stopEvent(); this make the user popdown broken
2218 onClick : function(e)
2220 Roo.log("menu.onClick");
2222 var t = this.findTargetItem(e);
2223 if(!t || t.isContainer){
2228 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2229 if(t == this.activeItem && t.shouldDeactivate(e)){
2230 this.activeItem.deactivate();
2231 delete this.activeItem;
2235 this.setActiveItem(t, true);
2243 Roo.log('pass click event');
2247 this.fireEvent("click", this, t, e);
2251 if(!t.href.length || t.href == '#'){
2252 (function() { _this.hide(); }).defer(100);
2257 onMouseOver : function(e){
2258 var t = this.findTargetItem(e);
2261 // if(t.canActivate && !t.disabled){
2262 // this.setActiveItem(t, true);
2266 this.fireEvent("mouseover", this, e, t);
2268 isVisible : function(){
2269 return !this.hidden;
2271 onMouseOut : function(e){
2272 var t = this.findTargetItem(e);
2275 // if(t == this.activeItem && t.shouldDeactivate(e)){
2276 // this.activeItem.deactivate();
2277 // delete this.activeItem;
2280 this.fireEvent("mouseout", this, e, t);
2285 * Displays this menu relative to another element
2286 * @param {String/HTMLElement/Roo.Element} element The element to align to
2287 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2288 * the element (defaults to this.defaultAlign)
2289 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2291 show : function(el, pos, parentMenu){
2292 this.parentMenu = parentMenu;
2296 this.fireEvent("beforeshow", this);
2297 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2300 * Displays this menu at a specific xy position
2301 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2302 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2304 showAt : function(xy, parentMenu, /* private: */_e){
2305 this.parentMenu = parentMenu;
2310 this.fireEvent("beforeshow", this);
2311 //xy = this.el.adjustForConstraints(xy);
2315 this.hideMenuItems();
2316 this.hidden = false;
2317 this.triggerEl.addClass('open');
2318 this.el.addClass('show');
2320 // reassign x when hitting right
2321 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2322 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2325 // reassign y when hitting bottom
2326 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2327 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2330 // but the list may align on trigger left or trigger top... should it be a properity?
2332 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2337 this.fireEvent("show", this);
2343 this.doFocus.defer(50, this);
2347 doFocus : function(){
2349 this.focusEl.focus();
2354 * Hides this menu and optionally all parent menus
2355 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2357 hide : function(deep)
2360 this.hideMenuItems();
2361 if(this.el && this.isVisible()){
2362 this.fireEvent("beforehide", this);
2363 if(this.activeItem){
2364 this.activeItem.deactivate();
2365 this.activeItem = null;
2367 this.triggerEl.removeClass('open');;
2368 this.el.removeClass('show');
2370 this.fireEvent("hide", this);
2372 if(deep === true && this.parentMenu){
2373 this.parentMenu.hide(true);
2377 onTriggerClick : function(e)
2379 Roo.log('trigger click');
2381 var target = e.getTarget();
2383 Roo.log(target.nodeName.toLowerCase());
2385 if(target.nodeName.toLowerCase() === 'i'){
2391 onTriggerPress : function(e)
2393 Roo.log('trigger press');
2394 //Roo.log(e.getTarget());
2395 // Roo.log(this.triggerEl.dom);
2397 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2398 var pel = Roo.get(e.getTarget());
2399 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2400 Roo.log('is treeview or dropdown?');
2404 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2408 if (this.isVisible()) {
2413 this.show(this.triggerEl, '?', false);
2416 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2423 hideMenuItems : function()
2425 Roo.log("hide Menu Items");
2429 //$(backdrop).remove()
2430 this.el.select('.open',true).each(function(aa) {
2432 aa.removeClass('open');
2433 //var parent = getParent($(this))
2434 //var relatedTarget = { relatedTarget: this }
2436 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2437 //if (e.isDefaultPrevented()) return
2438 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2441 addxtypeChild : function (tree, cntr) {
2442 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2444 this.menuitems.add(comp);
2456 this.getEl().dom.innerHTML = '';
2457 this.menuitems.clear();
2471 * @class Roo.bootstrap.MenuItem
2472 * @extends Roo.bootstrap.Component
2473 * Bootstrap MenuItem class
2474 * @cfg {String} html the menu label
2475 * @cfg {String} href the link
2476 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2477 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2478 * @cfg {Boolean} active used on sidebars to highlight active itesm
2479 * @cfg {String} fa favicon to show on left of menu item.
2480 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2484 * Create a new MenuItem
2485 * @param {Object} config The config object
2489 Roo.bootstrap.MenuItem = function(config){
2490 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2495 * The raw click event for the entire grid.
2496 * @param {Roo.bootstrap.MenuItem} this
2497 * @param {Roo.EventObject} e
2503 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2507 preventDefault: false,
2508 isContainer : false,
2512 getAutoCreate : function(){
2514 if(this.isContainer){
2517 cls: 'dropdown-menu-item '
2527 cls : 'dropdown-item',
2532 if (this.fa !== false) {
2535 cls : 'fa fa-' + this.fa
2544 cls: 'dropdown-menu-item',
2547 if (this.parent().type == 'treeview') {
2548 cfg.cls = 'treeview-menu';
2551 cfg.cls += ' active';
2556 anc.href = this.href || cfg.cn[0].href ;
2557 ctag.html = this.html || cfg.cn[0].html ;
2561 initEvents: function()
2563 if (this.parent().type == 'treeview') {
2564 this.el.select('a').on('click', this.onClick, this);
2568 this.menu.parentType = this.xtype;
2569 this.menu.triggerEl = this.el;
2570 this.menu = this.addxtype(Roo.apply({}, this.menu));
2574 onClick : function(e)
2576 Roo.log('item on click ');
2578 if(this.preventDefault){
2581 //this.parent().hideMenuItems();
2583 this.fireEvent('click', this, e);
2602 * @class Roo.bootstrap.MenuSeparator
2603 * @extends Roo.bootstrap.Component
2604 * Bootstrap MenuSeparator class
2607 * Create a new MenuItem
2608 * @param {Object} config The config object
2612 Roo.bootstrap.MenuSeparator = function(config){
2613 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2616 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2618 getAutoCreate : function(){
2637 * @class Roo.bootstrap.Modal
2638 * @extends Roo.bootstrap.Component
2639 * Bootstrap Modal class
2640 * @cfg {String} title Title of dialog
2641 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2642 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2643 * @cfg {Boolean} specificTitle default false
2644 * @cfg {Array} buttons Array of buttons or standard button set..
2645 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2646 * @cfg {Boolean} animate default true
2647 * @cfg {Boolean} allow_close default true
2648 * @cfg {Boolean} fitwindow default false
2649 * @cfg {String} size (sm|lg) default empty
2650 * @cfg {Number} max_width set the max width of modal
2654 * Create a new Modal Dialog
2655 * @param {Object} config The config object
2658 Roo.bootstrap.Modal = function(config){
2659 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2664 * The raw btnclick event for the button
2665 * @param {Roo.EventObject} e
2670 * Fire when dialog resize
2671 * @param {Roo.bootstrap.Modal} this
2672 * @param {Roo.EventObject} e
2676 this.buttons = this.buttons || [];
2679 this.tmpl = Roo.factory(this.tmpl);
2684 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2686 title : 'test dialog',
2696 specificTitle: false,
2698 buttonPosition: 'right',
2721 onRender : function(ct, position)
2723 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2726 var cfg = Roo.apply({}, this.getAutoCreate());
2729 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2731 //if (!cfg.name.length) {
2735 cfg.cls += ' ' + this.cls;
2738 cfg.style = this.style;
2740 this.el = Roo.get(document.body).createChild(cfg, position);
2742 //var type = this.el.dom.type;
2745 if(this.tabIndex !== undefined){
2746 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2749 this.dialogEl = this.el.select('.modal-dialog',true).first();
2750 this.bodyEl = this.el.select('.modal-body',true).first();
2751 this.closeEl = this.el.select('.modal-header .close', true).first();
2752 this.headerEl = this.el.select('.modal-header',true).first();
2753 this.titleEl = this.el.select('.modal-title',true).first();
2754 this.footerEl = this.el.select('.modal-footer',true).first();
2756 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2758 //this.el.addClass("x-dlg-modal");
2760 if (this.buttons.length) {
2761 Roo.each(this.buttons, function(bb) {
2762 var b = Roo.apply({}, bb);
2763 b.xns = b.xns || Roo.bootstrap;
2764 b.xtype = b.xtype || 'Button';
2765 if (typeof(b.listeners) == 'undefined') {
2766 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2769 var btn = Roo.factory(b);
2771 btn.render(this.getButtonContainer());
2775 // render the children.
2778 if(typeof(this.items) != 'undefined'){
2779 var items = this.items;
2782 for(var i =0;i < items.length;i++) {
2783 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2787 this.items = nitems;
2789 // where are these used - they used to be body/close/footer
2793 //this.el.addClass([this.fieldClass, this.cls]);
2797 getAutoCreate : function()
2801 html : this.html || ''
2806 cls : 'modal-title',
2810 if(this.specificTitle){
2816 if (this.allow_close && Roo.bootstrap.version == 3) {
2826 if (this.allow_close && Roo.bootstrap.version == 4) {
2836 if(this.size.length){
2837 size = 'modal-' + this.size;
2840 var footer = Roo.bootstrap.version == 3 ?
2842 cls : 'modal-footer',
2846 cls: 'btn-' + this.buttonPosition
2851 { // BS4 uses mr-auto on left buttons....
2852 cls : 'modal-footer'
2863 cls: "modal-dialog " + size,
2866 cls : "modal-content",
2869 cls : 'modal-header',
2884 modal.cls += ' fade';
2890 getChildContainer : function() {
2895 getButtonContainer : function() {
2897 return Roo.bootstrap.version == 4 ?
2898 this.el.select('.modal-footer',true).first()
2899 : this.el.select('.modal-footer div',true).first();
2902 initEvents : function()
2904 if (this.allow_close) {
2905 this.closeEl.on('click', this.hide, this);
2907 Roo.EventManager.onWindowResize(this.resize, this, true);
2914 this.maskEl.setSize(
2915 Roo.lib.Dom.getViewWidth(true),
2916 Roo.lib.Dom.getViewHeight(true)
2919 if (this.fitwindow) {
2921 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2922 this.height || Roo.lib.Dom.getViewportHeight(true) - 60
2927 if(this.max_width !== 0) {
2929 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2932 this.setSize(w, this.height);
2936 if(this.max_height) {
2937 this.setSize(w,Math.min(
2939 Roo.lib.Dom.getViewportHeight(true) - 60
2945 if(!this.fit_content) {
2946 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2950 this.setSize(w, Math.min(
2952 this.headerEl.getHeight() +
2953 this.footerEl.getHeight() +
2954 this.getChildHeight(this.bodyEl.dom.childNodes),
2955 Roo.lib.Dom.getViewportHeight(true) - 60)
2961 setSize : function(w,h)
2972 if (!this.rendered) {
2976 //this.el.setStyle('display', 'block');
2977 this.el.removeClass('hideing');
2978 this.el.dom.style.display='block';
2980 Roo.get(document.body).addClass('modal-open');
2982 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2985 this.el.addClass('show');
2986 this.el.addClass('in');
2989 this.el.addClass('show');
2990 this.el.addClass('in');
2993 // not sure how we can show data in here..
2995 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2998 Roo.get(document.body).addClass("x-body-masked");
3000 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3001 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3002 this.maskEl.dom.style.display = 'block';
3003 this.maskEl.addClass('show');
3008 this.fireEvent('show', this);
3010 // set zindex here - otherwise it appears to be ignored...
3011 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3014 this.items.forEach( function(e) {
3015 e.layout ? e.layout() : false;
3023 if(this.fireEvent("beforehide", this) !== false){
3025 this.maskEl.removeClass('show');
3027 this.maskEl.dom.style.display = '';
3028 Roo.get(document.body).removeClass("x-body-masked");
3029 this.el.removeClass('in');
3030 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3032 if(this.animate){ // why
3033 this.el.addClass('hideing');
3034 this.el.removeClass('show');
3036 if (!this.el.hasClass('hideing')) {
3037 return; // it's been shown again...
3040 this.el.dom.style.display='';
3042 Roo.get(document.body).removeClass('modal-open');
3043 this.el.removeClass('hideing');
3047 this.el.removeClass('show');
3048 this.el.dom.style.display='';
3049 Roo.get(document.body).removeClass('modal-open');
3052 this.fireEvent('hide', this);
3055 isVisible : function()
3058 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3062 addButton : function(str, cb)
3066 var b = Roo.apply({}, { html : str } );
3067 b.xns = b.xns || Roo.bootstrap;
3068 b.xtype = b.xtype || 'Button';
3069 if (typeof(b.listeners) == 'undefined') {
3070 b.listeners = { click : cb.createDelegate(this) };
3073 var btn = Roo.factory(b);
3075 btn.render(this.getButtonContainer());
3081 setDefaultButton : function(btn)
3083 //this.el.select('.modal-footer').()
3087 resizeTo: function(w,h)
3091 this.dialogEl.setWidth(w);
3092 if (this.diff === false) {
3093 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
3096 this.bodyEl.setHeight(h - this.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.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' + (this.btn_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);
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
7910 this.uploadProgress();
7912 }else if (o.clientValidation !== false){ // client validation failed
7913 this.failureType = Roo.form.Action.CLIENT_INVALID;
7914 this.form.afterAction(this, false);
7918 success : function(response)
7920 this.uploadComplete= true;
7921 if (this.haveProgress) {
7922 Roo.MessageBox.hide();
7926 var result = this.processResponse(response);
7927 if(result === true || result.success){
7928 this.form.afterAction(this, true);
7932 this.form.markInvalid(result.errors);
7933 this.failureType = Roo.form.Action.SERVER_INVALID;
7935 this.form.afterAction(this, false);
7937 failure : function(response)
7939 this.uploadComplete= true;
7940 if (this.haveProgress) {
7941 Roo.MessageBox.hide();
7944 this.response = response;
7945 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7946 this.form.afterAction(this, false);
7949 handleResponse : function(response){
7950 if(this.form.errorReader){
7951 var rs = this.form.errorReader.read(response);
7954 for(var i = 0, len = rs.records.length; i < len; i++) {
7955 var r = rs.records[i];
7959 if(errors.length < 1){
7963 success : rs.success,
7969 ret = Roo.decode(response.responseText);
7973 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7983 Roo.form.Action.Load = function(form, options){
7984 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7985 this.reader = this.form.reader;
7988 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7993 Roo.Ajax.request(Roo.apply(
7994 this.createCallback(), {
7995 method:this.getMethod(),
7996 url:this.getUrl(false),
7997 params:this.getParams()
8001 success : function(response){
8003 var result = this.processResponse(response);
8004 if(result === true || !result.success || !result.data){
8005 this.failureType = Roo.form.Action.LOAD_FAILURE;
8006 this.form.afterAction(this, false);
8009 this.form.clearInvalid();
8010 this.form.setValues(result.data);
8011 this.form.afterAction(this, true);
8014 handleResponse : function(response){
8015 if(this.form.reader){
8016 var rs = this.form.reader.read(response);
8017 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8019 success : rs.success,
8023 return Roo.decode(response.responseText);
8027 Roo.form.Action.ACTION_TYPES = {
8028 'load' : Roo.form.Action.Load,
8029 'submit' : Roo.form.Action.Submit
8038 * @class Roo.bootstrap.Form
8039 * @extends Roo.bootstrap.Component
8040 * Bootstrap Form class
8041 * @cfg {String} method GET | POST (default POST)
8042 * @cfg {String} labelAlign top | left (default top)
8043 * @cfg {String} align left | right - for navbars
8044 * @cfg {Boolean} loadMask load mask when submit (default true)
8049 * @param {Object} config The config object
8053 Roo.bootstrap.Form = function(config){
8055 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8057 Roo.bootstrap.Form.popover.apply();
8061 * @event clientvalidation
8062 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8063 * @param {Form} this
8064 * @param {Boolean} valid true if the form has passed client-side validation
8066 clientvalidation: true,
8068 * @event beforeaction
8069 * Fires before any action is performed. Return false to cancel the action.
8070 * @param {Form} this
8071 * @param {Action} action The action to be performed
8075 * @event actionfailed
8076 * Fires when an action fails.
8077 * @param {Form} this
8078 * @param {Action} action The action that failed
8080 actionfailed : true,
8082 * @event actioncomplete
8083 * Fires when an action is completed.
8084 * @param {Form} this
8085 * @param {Action} action The action that completed
8087 actioncomplete : true
8091 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8094 * @cfg {String} method
8095 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8100 * The URL to use for form actions if one isn't supplied in the action options.
8103 * @cfg {Boolean} fileUpload
8104 * Set to true if this form is a file upload.
8108 * @cfg {Object} baseParams
8109 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8113 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8117 * @cfg {Sting} align (left|right) for navbar forms
8122 activeAction : null,
8125 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8126 * element by passing it or its id or mask the form itself by passing in true.
8129 waitMsgTarget : false,
8134 * @cfg {Boolean} errorMask (true|false) default false
8139 * @cfg {Number} maskOffset Default 100
8144 * @cfg {Boolean} maskBody
8148 getAutoCreate : function(){
8152 method : this.method || 'POST',
8153 id : this.id || Roo.id(),
8156 if (this.parent().xtype.match(/^Nav/)) {
8157 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8161 if (this.labelAlign == 'left' ) {
8162 cfg.cls += ' form-horizontal';
8168 initEvents : function()
8170 this.el.on('submit', this.onSubmit, this);
8171 // this was added as random key presses on the form where triggering form submit.
8172 this.el.on('keypress', function(e) {
8173 if (e.getCharCode() != 13) {
8176 // we might need to allow it for textareas.. and some other items.
8177 // check e.getTarget().
8179 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8183 Roo.log("keypress blocked");
8191 onSubmit : function(e){
8196 * Returns true if client-side validation on the form is successful.
8199 isValid : function(){
8200 var items = this.getItems();
8204 items.each(function(f){
8210 Roo.log('invalid field: ' + f.name);
8214 if(!target && f.el.isVisible(true)){
8220 if(this.errorMask && !valid){
8221 Roo.bootstrap.Form.popover.mask(this, target);
8228 * Returns true if any fields in this form have changed since their original load.
8231 isDirty : function(){
8233 var items = this.getItems();
8234 items.each(function(f){
8244 * Performs a predefined action (submit or load) or custom actions you define on this form.
8245 * @param {String} actionName The name of the action type
8246 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8247 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8248 * accept other config options):
8250 Property Type Description
8251 ---------------- --------------- ----------------------------------------------------------------------------------
8252 url String The url for the action (defaults to the form's url)
8253 method String The form method to use (defaults to the form's method, or POST if not defined)
8254 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8255 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8256 validate the form on the client (defaults to false)
8258 * @return {BasicForm} this
8260 doAction : function(action, options){
8261 if(typeof action == 'string'){
8262 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8264 if(this.fireEvent('beforeaction', this, action) !== false){
8265 this.beforeAction(action);
8266 action.run.defer(100, action);
8272 beforeAction : function(action){
8273 var o = action.options;
8278 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8280 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8283 // not really supported yet.. ??
8285 //if(this.waitMsgTarget === true){
8286 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8287 //}else if(this.waitMsgTarget){
8288 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8289 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8291 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8297 afterAction : function(action, success){
8298 this.activeAction = null;
8299 var o = action.options;
8304 Roo.get(document.body).unmask();
8310 //if(this.waitMsgTarget === true){
8311 // this.el.unmask();
8312 //}else if(this.waitMsgTarget){
8313 // this.waitMsgTarget.unmask();
8315 // Roo.MessageBox.updateProgress(1);
8316 // Roo.MessageBox.hide();
8323 Roo.callback(o.success, o.scope, [this, action]);
8324 this.fireEvent('actioncomplete', this, action);
8328 // failure condition..
8329 // we have a scenario where updates need confirming.
8330 // eg. if a locking scenario exists..
8331 // we look for { errors : { needs_confirm : true }} in the response.
8333 (typeof(action.result) != 'undefined') &&
8334 (typeof(action.result.errors) != 'undefined') &&
8335 (typeof(action.result.errors.needs_confirm) != 'undefined')
8338 Roo.log("not supported yet");
8341 Roo.MessageBox.confirm(
8342 "Change requires confirmation",
8343 action.result.errorMsg,
8348 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8358 Roo.callback(o.failure, o.scope, [this, action]);
8359 // show an error message if no failed handler is set..
8360 if (!this.hasListener('actionfailed')) {
8361 Roo.log("need to add dialog support");
8363 Roo.MessageBox.alert("Error",
8364 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8365 action.result.errorMsg :
8366 "Saving Failed, please check your entries or try again"
8371 this.fireEvent('actionfailed', this, action);
8376 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8377 * @param {String} id The value to search for
8380 findField : function(id){
8381 var items = this.getItems();
8382 var field = items.get(id);
8384 items.each(function(f){
8385 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8392 return field || null;
8395 * Mark fields in this form invalid in bulk.
8396 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8397 * @return {BasicForm} this
8399 markInvalid : function(errors){
8400 if(errors instanceof Array){
8401 for(var i = 0, len = errors.length; i < len; i++){
8402 var fieldError = errors[i];
8403 var f = this.findField(fieldError.id);
8405 f.markInvalid(fieldError.msg);
8411 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8412 field.markInvalid(errors[id]);
8416 //Roo.each(this.childForms || [], function (f) {
8417 // f.markInvalid(errors);
8424 * Set values for fields in this form in bulk.
8425 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8426 * @return {BasicForm} this
8428 setValues : function(values){
8429 if(values instanceof Array){ // array of objects
8430 for(var i = 0, len = values.length; i < len; i++){
8432 var f = this.findField(v.id);
8434 f.setValue(v.value);
8435 if(this.trackResetOnLoad){
8436 f.originalValue = f.getValue();
8440 }else{ // object hash
8443 if(typeof values[id] != 'function' && (field = this.findField(id))){
8445 if (field.setFromData &&
8447 field.displayField &&
8448 // combos' with local stores can
8449 // be queried via setValue()
8450 // to set their value..
8451 (field.store && !field.store.isLocal)
8455 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8456 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8457 field.setFromData(sd);
8459 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8461 field.setFromData(values);
8464 field.setValue(values[id]);
8468 if(this.trackResetOnLoad){
8469 field.originalValue = field.getValue();
8475 //Roo.each(this.childForms || [], function (f) {
8476 // f.setValues(values);
8483 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8484 * they are returned as an array.
8485 * @param {Boolean} asString
8488 getValues : function(asString){
8489 //if (this.childForms) {
8490 // copy values from the child forms
8491 // Roo.each(this.childForms, function (f) {
8492 // this.setValues(f.getValues());
8498 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8499 if(asString === true){
8502 return Roo.urlDecode(fs);
8506 * Returns the fields in this form as an object with key/value pairs.
8507 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8510 getFieldValues : function(with_hidden)
8512 var items = this.getItems();
8514 items.each(function(f){
8520 var v = f.getValue();
8522 if (f.inputType =='radio') {
8523 if (typeof(ret[f.getName()]) == 'undefined') {
8524 ret[f.getName()] = ''; // empty..
8527 if (!f.el.dom.checked) {
8535 if(f.xtype == 'MoneyField'){
8536 ret[f.currencyName] = f.getCurrency();
8539 // not sure if this supported any more..
8540 if ((typeof(v) == 'object') && f.getRawValue) {
8541 v = f.getRawValue() ; // dates..
8543 // combo boxes where name != hiddenName...
8544 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8545 ret[f.name] = f.getRawValue();
8547 ret[f.getName()] = v;
8554 * Clears all invalid messages in this form.
8555 * @return {BasicForm} this
8557 clearInvalid : function(){
8558 var items = this.getItems();
8560 items.each(function(f){
8569 * @return {BasicForm} this
8572 var items = this.getItems();
8573 items.each(function(f){
8577 Roo.each(this.childForms || [], function (f) {
8585 getItems : function()
8587 var r=new Roo.util.MixedCollection(false, function(o){
8588 return o.id || (o.id = Roo.id());
8590 var iter = function(el) {
8597 Roo.each(el.items,function(e) {
8606 hideFields : function(items)
8608 Roo.each(items, function(i){
8610 var f = this.findField(i);
8621 showFields : function(items)
8623 Roo.each(items, function(i){
8625 var f = this.findField(i);
8638 Roo.apply(Roo.bootstrap.Form, {
8665 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8666 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8667 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8668 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8671 this.maskEl.top.enableDisplayMode("block");
8672 this.maskEl.left.enableDisplayMode("block");
8673 this.maskEl.bottom.enableDisplayMode("block");
8674 this.maskEl.right.enableDisplayMode("block");
8676 this.toolTip = new Roo.bootstrap.Tooltip({
8677 cls : 'roo-form-error-popover',
8679 'left' : ['r-l', [-2,0], 'right'],
8680 'right' : ['l-r', [2,0], 'left'],
8681 'bottom' : ['tl-bl', [0,2], 'top'],
8682 'top' : [ 'bl-tl', [0,-2], 'bottom']
8686 this.toolTip.render(Roo.get(document.body));
8688 this.toolTip.el.enableDisplayMode("block");
8690 Roo.get(document.body).on('click', function(){
8694 Roo.get(document.body).on('touchstart', function(){
8698 this.isApplied = true
8701 mask : function(form, target)
8705 this.target = target;
8707 if(!this.form.errorMask || !target.el){
8711 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8713 Roo.log(scrollable);
8715 var ot = this.target.el.calcOffsetsTo(scrollable);
8717 var scrollTo = ot[1] - this.form.maskOffset;
8719 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8721 scrollable.scrollTo('top', scrollTo);
8723 var box = this.target.el.getBox();
8725 var zIndex = Roo.bootstrap.Modal.zIndex++;
8728 this.maskEl.top.setStyle('position', 'absolute');
8729 this.maskEl.top.setStyle('z-index', zIndex);
8730 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8731 this.maskEl.top.setLeft(0);
8732 this.maskEl.top.setTop(0);
8733 this.maskEl.top.show();
8735 this.maskEl.left.setStyle('position', 'absolute');
8736 this.maskEl.left.setStyle('z-index', zIndex);
8737 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8738 this.maskEl.left.setLeft(0);
8739 this.maskEl.left.setTop(box.y - this.padding);
8740 this.maskEl.left.show();
8742 this.maskEl.bottom.setStyle('position', 'absolute');
8743 this.maskEl.bottom.setStyle('z-index', zIndex);
8744 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8745 this.maskEl.bottom.setLeft(0);
8746 this.maskEl.bottom.setTop(box.bottom + this.padding);
8747 this.maskEl.bottom.show();
8749 this.maskEl.right.setStyle('position', 'absolute');
8750 this.maskEl.right.setStyle('z-index', zIndex);
8751 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8752 this.maskEl.right.setLeft(box.right + this.padding);
8753 this.maskEl.right.setTop(box.y - this.padding);
8754 this.maskEl.right.show();
8756 this.toolTip.bindEl = this.target.el;
8758 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8760 var tip = this.target.blankText;
8762 if(this.target.getValue() !== '' ) {
8764 if (this.target.invalidText.length) {
8765 tip = this.target.invalidText;
8766 } else if (this.target.regexText.length){
8767 tip = this.target.regexText;
8771 this.toolTip.show(tip);
8773 this.intervalID = window.setInterval(function() {
8774 Roo.bootstrap.Form.popover.unmask();
8777 window.onwheel = function(){ return false;};
8779 (function(){ this.isMasked = true; }).defer(500, this);
8785 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8789 this.maskEl.top.setStyle('position', 'absolute');
8790 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8791 this.maskEl.top.hide();
8793 this.maskEl.left.setStyle('position', 'absolute');
8794 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8795 this.maskEl.left.hide();
8797 this.maskEl.bottom.setStyle('position', 'absolute');
8798 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8799 this.maskEl.bottom.hide();
8801 this.maskEl.right.setStyle('position', 'absolute');
8802 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8803 this.maskEl.right.hide();
8805 this.toolTip.hide();
8807 this.toolTip.el.hide();
8809 window.onwheel = function(){ return true;};
8811 if(this.intervalID){
8812 window.clearInterval(this.intervalID);
8813 this.intervalID = false;
8816 this.isMasked = false;
8826 * Ext JS Library 1.1.1
8827 * Copyright(c) 2006-2007, Ext JS, LLC.
8829 * Originally Released Under LGPL - original licence link has changed is not relivant.
8832 * <script type="text/javascript">
8835 * @class Roo.form.VTypes
8836 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8839 Roo.form.VTypes = function(){
8840 // closure these in so they are only created once.
8841 var alpha = /^[a-zA-Z_]+$/;
8842 var alphanum = /^[a-zA-Z0-9_]+$/;
8843 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8844 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8846 // All these messages and functions are configurable
8849 * The function used to validate email addresses
8850 * @param {String} value The email address
8852 'email' : function(v){
8853 return email.test(v);
8856 * The error text to display when the email validation function returns false
8859 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8861 * The keystroke filter mask to be applied on email input
8864 'emailMask' : /[a-z0-9_\.\-@]/i,
8867 * The function used to validate URLs
8868 * @param {String} value The URL
8870 'url' : function(v){
8874 * The error text to display when the url validation function returns false
8877 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8880 * The function used to validate alpha values
8881 * @param {String} value The value
8883 'alpha' : function(v){
8884 return alpha.test(v);
8887 * The error text to display when the alpha validation function returns false
8890 'alphaText' : 'This field should only contain letters and _',
8892 * The keystroke filter mask to be applied on alpha input
8895 'alphaMask' : /[a-z_]/i,
8898 * The function used to validate alphanumeric values
8899 * @param {String} value The value
8901 'alphanum' : function(v){
8902 return alphanum.test(v);
8905 * The error text to display when the alphanumeric validation function returns false
8908 'alphanumText' : 'This field should only contain letters, numbers and _',
8910 * The keystroke filter mask to be applied on alphanumeric input
8913 'alphanumMask' : /[a-z0-9_]/i
8923 * @class Roo.bootstrap.Input
8924 * @extends Roo.bootstrap.Component
8925 * Bootstrap Input class
8926 * @cfg {Boolean} disabled is it disabled
8927 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8928 * @cfg {String} name name of the input
8929 * @cfg {string} fieldLabel - the label associated
8930 * @cfg {string} placeholder - placeholder to put in text.
8931 * @cfg {string} before - input group add on before
8932 * @cfg {string} after - input group add on after
8933 * @cfg {string} size - (lg|sm) or leave empty..
8934 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8935 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8936 * @cfg {Number} md colspan out of 12 for computer-sized screens
8937 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8938 * @cfg {string} value default value of the input
8939 * @cfg {Number} labelWidth set the width of label
8940 * @cfg {Number} labellg set the width of label (1-12)
8941 * @cfg {Number} labelmd set the width of label (1-12)
8942 * @cfg {Number} labelsm set the width of label (1-12)
8943 * @cfg {Number} labelxs set the width of label (1-12)
8944 * @cfg {String} labelAlign (top|left)
8945 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8946 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8947 * @cfg {String} indicatorpos (left|right) default left
8948 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8949 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8951 * @cfg {String} align (left|center|right) Default left
8952 * @cfg {Boolean} forceFeedback (true|false) Default false
8955 * Create a new Input
8956 * @param {Object} config The config object
8959 Roo.bootstrap.Input = function(config){
8961 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8966 * Fires when this field receives input focus.
8967 * @param {Roo.form.Field} this
8972 * Fires when this field loses input focus.
8973 * @param {Roo.form.Field} this
8978 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8979 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8980 * @param {Roo.form.Field} this
8981 * @param {Roo.EventObject} e The event object
8986 * Fires just before the field blurs if the field value has changed.
8987 * @param {Roo.form.Field} this
8988 * @param {Mixed} newValue The new value
8989 * @param {Mixed} oldValue The original value
8994 * Fires after the field has been marked as invalid.
8995 * @param {Roo.form.Field} this
8996 * @param {String} msg The validation message
9001 * Fires after the field has been validated with no errors.
9002 * @param {Roo.form.Field} this
9007 * Fires after the key up
9008 * @param {Roo.form.Field} this
9009 * @param {Roo.EventObject} e The event Object
9015 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9017 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9018 automatic validation (defaults to "keyup").
9020 validationEvent : "keyup",
9022 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9024 validateOnBlur : true,
9026 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9028 validationDelay : 250,
9030 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9032 focusClass : "x-form-focus", // not needed???
9036 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9038 invalidClass : "has-warning",
9041 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9043 validClass : "has-success",
9046 * @cfg {Boolean} hasFeedback (true|false) default true
9051 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9053 invalidFeedbackClass : "glyphicon-warning-sign",
9056 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9058 validFeedbackClass : "glyphicon-ok",
9061 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9063 selectOnFocus : false,
9066 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9070 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9075 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9077 disableKeyFilter : false,
9080 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9084 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9088 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9090 blankText : "Please complete this mandatory field",
9093 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9097 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9099 maxLength : Number.MAX_VALUE,
9101 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9103 minLengthText : "The minimum length for this field is {0}",
9105 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9107 maxLengthText : "The maximum length for this field is {0}",
9111 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9112 * If available, this function will be called only after the basic validators all return true, and will be passed the
9113 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9117 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9118 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9119 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9123 * @cfg {String} regexText -- Depricated - use Invalid Text
9128 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9134 autocomplete: false,
9153 formatedValue : false,
9154 forceFeedback : false,
9156 indicatorpos : 'left',
9166 parentLabelAlign : function()
9169 while (parent.parent()) {
9170 parent = parent.parent();
9171 if (typeof(parent.labelAlign) !='undefined') {
9172 return parent.labelAlign;
9179 getAutoCreate : function()
9181 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9187 if(this.inputType != 'hidden'){
9188 cfg.cls = 'form-group' //input-group
9194 type : this.inputType,
9196 cls : 'form-control',
9197 placeholder : this.placeholder || '',
9198 autocomplete : this.autocomplete || 'new-password'
9201 if(this.capture.length){
9202 input.capture = this.capture;
9205 if(this.accept.length){
9206 input.accept = this.accept + "/*";
9210 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9213 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9214 input.maxLength = this.maxLength;
9217 if (this.disabled) {
9218 input.disabled=true;
9221 if (this.readOnly) {
9222 input.readonly=true;
9226 input.name = this.name;
9230 input.cls += ' input-' + this.size;
9234 ['xs','sm','md','lg'].map(function(size){
9235 if (settings[size]) {
9236 cfg.cls += ' col-' + size + '-' + settings[size];
9240 var inputblock = input;
9244 cls: 'glyphicon form-control-feedback'
9247 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9250 cls : 'has-feedback',
9258 if (this.before || this.after) {
9261 cls : 'input-group',
9265 if (this.before && typeof(this.before) == 'string') {
9267 inputblock.cn.push({
9269 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9273 if (this.before && typeof(this.before) == 'object') {
9274 this.before = Roo.factory(this.before);
9276 inputblock.cn.push({
9278 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9279 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9283 inputblock.cn.push(input);
9285 if (this.after && typeof(this.after) == 'string') {
9286 inputblock.cn.push({
9288 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9292 if (this.after && typeof(this.after) == 'object') {
9293 this.after = Roo.factory(this.after);
9295 inputblock.cn.push({
9297 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9298 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9302 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9303 inputblock.cls += ' has-feedback';
9304 inputblock.cn.push(feedback);
9309 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9310 tooltip : 'This field is required'
9312 if (Roo.bootstrap.version == 4) {
9315 style : 'display-none'
9318 if (align ==='left' && this.fieldLabel.length) {
9320 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9327 cls : 'control-label col-form-label',
9328 html : this.fieldLabel
9339 var labelCfg = cfg.cn[1];
9340 var contentCfg = cfg.cn[2];
9342 if(this.indicatorpos == 'right'){
9347 cls : 'control-label col-form-label',
9351 html : this.fieldLabel
9365 labelCfg = cfg.cn[0];
9366 contentCfg = cfg.cn[1];
9370 if(this.labelWidth > 12){
9371 labelCfg.style = "width: " + this.labelWidth + 'px';
9374 if(this.labelWidth < 13 && this.labelmd == 0){
9375 this.labelmd = this.labelWidth;
9378 if(this.labellg > 0){
9379 labelCfg.cls += ' col-lg-' + this.labellg;
9380 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9383 if(this.labelmd > 0){
9384 labelCfg.cls += ' col-md-' + this.labelmd;
9385 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9388 if(this.labelsm > 0){
9389 labelCfg.cls += ' col-sm-' + this.labelsm;
9390 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9393 if(this.labelxs > 0){
9394 labelCfg.cls += ' col-xs-' + this.labelxs;
9395 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9399 } else if ( this.fieldLabel.length) {
9404 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9405 tooltip : 'This field is required'
9409 //cls : 'input-group-addon',
9410 html : this.fieldLabel
9418 if(this.indicatorpos == 'right'){
9423 //cls : 'input-group-addon',
9424 html : this.fieldLabel
9429 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9430 tooltip : 'This field is required'
9450 if (this.parentType === 'Navbar' && this.parent().bar) {
9451 cfg.cls += ' navbar-form';
9454 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9455 // on BS4 we do this only if not form
9456 cfg.cls += ' navbar-form';
9464 * return the real input element.
9466 inputEl: function ()
9468 return this.el.select('input.form-control',true).first();
9471 tooltipEl : function()
9473 return this.inputEl();
9476 indicatorEl : function()
9478 if (Roo.bootstrap.version == 4) {
9479 return false; // not enabled in v4 yet.
9482 var indicator = this.el.select('i.roo-required-indicator',true).first();
9492 setDisabled : function(v)
9494 var i = this.inputEl().dom;
9496 i.removeAttribute('disabled');
9500 i.setAttribute('disabled','true');
9502 initEvents : function()
9505 this.inputEl().on("keydown" , this.fireKey, this);
9506 this.inputEl().on("focus", this.onFocus, this);
9507 this.inputEl().on("blur", this.onBlur, this);
9509 this.inputEl().relayEvent('keyup', this);
9511 this.indicator = this.indicatorEl();
9514 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9517 // reference to original value for reset
9518 this.originalValue = this.getValue();
9519 //Roo.form.TextField.superclass.initEvents.call(this);
9520 if(this.validationEvent == 'keyup'){
9521 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9522 this.inputEl().on('keyup', this.filterValidation, this);
9524 else if(this.validationEvent !== false){
9525 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9528 if(this.selectOnFocus){
9529 this.on("focus", this.preFocus, this);
9532 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9533 this.inputEl().on("keypress", this.filterKeys, this);
9535 this.inputEl().relayEvent('keypress', this);
9538 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9539 this.el.on("click", this.autoSize, this);
9542 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9543 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9546 if (typeof(this.before) == 'object') {
9547 this.before.render(this.el.select('.roo-input-before',true).first());
9549 if (typeof(this.after) == 'object') {
9550 this.after.render(this.el.select('.roo-input-after',true).first());
9553 this.inputEl().on('change', this.onChange, this);
9556 filterValidation : function(e){
9557 if(!e.isNavKeyPress()){
9558 this.validationTask.delay(this.validationDelay);
9562 * Validates the field value
9563 * @return {Boolean} True if the value is valid, else false
9565 validate : function(){
9566 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9567 if(this.disabled || this.validateValue(this.getRawValue())){
9578 * Validates a value according to the field's validation rules and marks the field as invalid
9579 * if the validation fails
9580 * @param {Mixed} value The value to validate
9581 * @return {Boolean} True if the value is valid, else false
9583 validateValue : function(value)
9585 if(this.getVisibilityEl().hasClass('hidden')){
9589 if(value.length < 1) { // if it's blank
9590 if(this.allowBlank){
9596 if(value.length < this.minLength){
9599 if(value.length > this.maxLength){
9603 var vt = Roo.form.VTypes;
9604 if(!vt[this.vtype](value, this)){
9608 if(typeof this.validator == "function"){
9609 var msg = this.validator(value);
9613 if (typeof(msg) == 'string') {
9614 this.invalidText = msg;
9618 if(this.regex && !this.regex.test(value)){
9626 fireKey : function(e){
9627 //Roo.log('field ' + e.getKey());
9628 if(e.isNavKeyPress()){
9629 this.fireEvent("specialkey", this, e);
9632 focus : function (selectText){
9634 this.inputEl().focus();
9635 if(selectText === true){
9636 this.inputEl().dom.select();
9642 onFocus : function(){
9643 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9644 // this.el.addClass(this.focusClass);
9647 this.hasFocus = true;
9648 this.startValue = this.getValue();
9649 this.fireEvent("focus", this);
9653 beforeBlur : Roo.emptyFn,
9657 onBlur : function(){
9659 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9660 //this.el.removeClass(this.focusClass);
9662 this.hasFocus = false;
9663 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9666 var v = this.getValue();
9667 if(String(v) !== String(this.startValue)){
9668 this.fireEvent('change', this, v, this.startValue);
9670 this.fireEvent("blur", this);
9673 onChange : function(e)
9675 var v = this.getValue();
9676 if(String(v) !== String(this.startValue)){
9677 this.fireEvent('change', this, v, this.startValue);
9683 * Resets the current field value to the originally loaded value and clears any validation messages
9686 this.setValue(this.originalValue);
9690 * Returns the name of the field
9691 * @return {Mixed} name The name field
9693 getName: function(){
9697 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9698 * @return {Mixed} value The field value
9700 getValue : function(){
9702 var v = this.inputEl().getValue();
9707 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9708 * @return {Mixed} value The field value
9710 getRawValue : function(){
9711 var v = this.inputEl().getValue();
9717 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9718 * @param {Mixed} value The value to set
9720 setRawValue : function(v){
9721 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9724 selectText : function(start, end){
9725 var v = this.getRawValue();
9727 start = start === undefined ? 0 : start;
9728 end = end === undefined ? v.length : end;
9729 var d = this.inputEl().dom;
9730 if(d.setSelectionRange){
9731 d.setSelectionRange(start, end);
9732 }else if(d.createTextRange){
9733 var range = d.createTextRange();
9734 range.moveStart("character", start);
9735 range.moveEnd("character", v.length-end);
9742 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9743 * @param {Mixed} value The value to set
9745 setValue : function(v){
9748 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9754 processValue : function(value){
9755 if(this.stripCharsRe){
9756 var newValue = value.replace(this.stripCharsRe, '');
9757 if(newValue !== value){
9758 this.setRawValue(newValue);
9765 preFocus : function(){
9767 if(this.selectOnFocus){
9768 this.inputEl().dom.select();
9771 filterKeys : function(e){
9773 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9776 var c = e.getCharCode(), cc = String.fromCharCode(c);
9777 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9780 if(!this.maskRe.test(cc)){
9785 * Clear any invalid styles/messages for this field
9787 clearInvalid : function(){
9789 if(!this.el || this.preventMark){ // not rendered
9794 this.el.removeClass([this.invalidClass, 'is-invalid']);
9796 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9798 var feedback = this.el.select('.form-control-feedback', true).first();
9801 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9807 this.indicator.removeClass('visible');
9808 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9811 this.fireEvent('valid', this);
9815 * Mark this field as valid
9817 markValid : function()
9819 if(!this.el || this.preventMark){ // not rendered...
9823 this.el.removeClass([this.invalidClass, this.validClass]);
9824 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9826 var feedback = this.el.select('.form-control-feedback', true).first();
9829 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9833 this.indicator.removeClass('visible');
9834 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9841 if(this.allowBlank && !this.getRawValue().length){
9844 if (Roo.bootstrap.version == 3) {
9845 this.el.addClass(this.validClass);
9847 this.inputEl().addClass('is-valid');
9850 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9852 var feedback = this.el.select('.form-control-feedback', true).first();
9855 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9856 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9861 this.fireEvent('valid', this);
9865 * Mark this field as invalid
9866 * @param {String} msg The validation message
9868 markInvalid : function(msg)
9870 if(!this.el || this.preventMark){ // not rendered
9874 this.el.removeClass([this.invalidClass, this.validClass]);
9875 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9877 var feedback = this.el.select('.form-control-feedback', true).first();
9880 this.el.select('.form-control-feedback', true).first().removeClass(
9881 [this.invalidFeedbackClass, this.validFeedbackClass]);
9888 if(this.allowBlank && !this.getRawValue().length){
9893 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9894 this.indicator.addClass('visible');
9896 if (Roo.bootstrap.version == 3) {
9897 this.el.addClass(this.invalidClass);
9899 this.inputEl().addClass('is-invalid');
9904 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9906 var feedback = this.el.select('.form-control-feedback', true).first();
9909 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9911 if(this.getValue().length || this.forceFeedback){
9912 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9919 this.fireEvent('invalid', this, msg);
9922 SafariOnKeyDown : function(event)
9924 // this is a workaround for a password hang bug on chrome/ webkit.
9925 if (this.inputEl().dom.type != 'password') {
9929 var isSelectAll = false;
9931 if(this.inputEl().dom.selectionEnd > 0){
9932 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9934 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9935 event.preventDefault();
9940 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9942 event.preventDefault();
9943 // this is very hacky as keydown always get's upper case.
9945 var cc = String.fromCharCode(event.getCharCode());
9946 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9950 adjustWidth : function(tag, w){
9951 tag = tag.toLowerCase();
9952 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9953 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9957 if(tag == 'textarea'){
9960 }else if(Roo.isOpera){
9964 if(tag == 'textarea'){
9972 setFieldLabel : function(v)
9978 if(this.indicatorEl()){
9979 var ar = this.el.select('label > span',true);
9981 if (ar.elements.length) {
9982 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9983 this.fieldLabel = v;
9987 var br = this.el.select('label',true);
9989 if(br.elements.length) {
9990 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9991 this.fieldLabel = v;
9995 Roo.log('Cannot Found any of label > span || label in input');
9999 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10000 this.fieldLabel = v;
10015 * @class Roo.bootstrap.TextArea
10016 * @extends Roo.bootstrap.Input
10017 * Bootstrap TextArea class
10018 * @cfg {Number} cols Specifies the visible width of a text area
10019 * @cfg {Number} rows Specifies the visible number of lines in a text area
10020 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10021 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10022 * @cfg {string} html text
10025 * Create a new TextArea
10026 * @param {Object} config The config object
10029 Roo.bootstrap.TextArea = function(config){
10030 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10034 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10044 getAutoCreate : function(){
10046 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10052 if(this.inputType != 'hidden'){
10053 cfg.cls = 'form-group' //input-group
10061 value : this.value || '',
10062 html: this.html || '',
10063 cls : 'form-control',
10064 placeholder : this.placeholder || ''
10068 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10069 input.maxLength = this.maxLength;
10073 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10077 input.cols = this.cols;
10080 if (this.readOnly) {
10081 input.readonly = true;
10085 input.name = this.name;
10089 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10093 ['xs','sm','md','lg'].map(function(size){
10094 if (settings[size]) {
10095 cfg.cls += ' col-' + size + '-' + settings[size];
10099 var inputblock = input;
10101 if(this.hasFeedback && !this.allowBlank){
10105 cls: 'glyphicon form-control-feedback'
10109 cls : 'has-feedback',
10118 if (this.before || this.after) {
10121 cls : 'input-group',
10125 inputblock.cn.push({
10127 cls : 'input-group-addon',
10132 inputblock.cn.push(input);
10134 if(this.hasFeedback && !this.allowBlank){
10135 inputblock.cls += ' has-feedback';
10136 inputblock.cn.push(feedback);
10140 inputblock.cn.push({
10142 cls : 'input-group-addon',
10149 if (align ==='left' && this.fieldLabel.length) {
10154 cls : 'control-label',
10155 html : this.fieldLabel
10166 if(this.labelWidth > 12){
10167 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10170 if(this.labelWidth < 13 && this.labelmd == 0){
10171 this.labelmd = this.labelWidth;
10174 if(this.labellg > 0){
10175 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10176 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10179 if(this.labelmd > 0){
10180 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10181 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10184 if(this.labelsm > 0){
10185 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10186 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10189 if(this.labelxs > 0){
10190 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10191 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10194 } else if ( this.fieldLabel.length) {
10199 //cls : 'input-group-addon',
10200 html : this.fieldLabel
10218 if (this.disabled) {
10219 input.disabled=true;
10226 * return the real textarea element.
10228 inputEl: function ()
10230 return this.el.select('textarea.form-control',true).first();
10234 * Clear any invalid styles/messages for this field
10236 clearInvalid : function()
10239 if(!this.el || this.preventMark){ // not rendered
10243 var label = this.el.select('label', true).first();
10244 var icon = this.el.select('i.fa-star', true).first();
10249 this.el.removeClass( this.validClass);
10250 this.inputEl().removeClass('is-invalid');
10252 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10254 var feedback = this.el.select('.form-control-feedback', true).first();
10257 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10262 this.fireEvent('valid', this);
10266 * Mark this field as valid
10268 markValid : function()
10270 if(!this.el || this.preventMark){ // not rendered
10274 this.el.removeClass([this.invalidClass, this.validClass]);
10275 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10277 var feedback = this.el.select('.form-control-feedback', true).first();
10280 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10283 if(this.disabled || this.allowBlank){
10287 var label = this.el.select('label', true).first();
10288 var icon = this.el.select('i.fa-star', true).first();
10293 if (Roo.bootstrap.version == 3) {
10294 this.el.addClass(this.validClass);
10296 this.inputEl().addClass('is-valid');
10300 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10302 var feedback = this.el.select('.form-control-feedback', true).first();
10305 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10306 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10311 this.fireEvent('valid', this);
10315 * Mark this field as invalid
10316 * @param {String} msg The validation message
10318 markInvalid : function(msg)
10320 if(!this.el || this.preventMark){ // not rendered
10324 this.el.removeClass([this.invalidClass, this.validClass]);
10325 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10327 var feedback = this.el.select('.form-control-feedback', true).first();
10330 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10333 if(this.disabled || this.allowBlank){
10337 var label = this.el.select('label', true).first();
10338 var icon = this.el.select('i.fa-star', true).first();
10340 if(!this.getValue().length && label && !icon){
10341 this.el.createChild({
10343 cls : 'text-danger fa fa-lg fa-star',
10344 tooltip : 'This field is required',
10345 style : 'margin-right:5px;'
10349 if (Roo.bootstrap.version == 3) {
10350 this.el.addClass(this.invalidClass);
10352 this.inputEl().addClass('is-invalid');
10355 // fixme ... this may be depricated need to test..
10356 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10358 var feedback = this.el.select('.form-control-feedback', true).first();
10361 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10363 if(this.getValue().length || this.forceFeedback){
10364 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10371 this.fireEvent('invalid', this, msg);
10379 * trigger field - base class for combo..
10384 * @class Roo.bootstrap.TriggerField
10385 * @extends Roo.bootstrap.Input
10386 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10387 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10388 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10389 * for which you can provide a custom implementation. For example:
10391 var trigger = new Roo.bootstrap.TriggerField();
10392 trigger.onTriggerClick = myTriggerFn;
10393 trigger.applyTo('my-field');
10396 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10397 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10398 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10399 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10400 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10403 * Create a new TriggerField.
10404 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10405 * to the base TextField)
10407 Roo.bootstrap.TriggerField = function(config){
10408 this.mimicing = false;
10409 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10412 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10414 * @cfg {String} triggerClass A CSS class to apply to the trigger
10417 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10422 * @cfg {Boolean} removable (true|false) special filter default false
10426 /** @cfg {Boolean} grow @hide */
10427 /** @cfg {Number} growMin @hide */
10428 /** @cfg {Number} growMax @hide */
10434 autoSize: Roo.emptyFn,
10438 deferHeight : true,
10441 actionMode : 'wrap',
10446 getAutoCreate : function(){
10448 var align = this.labelAlign || this.parentLabelAlign();
10453 cls: 'form-group' //input-group
10460 type : this.inputType,
10461 cls : 'form-control',
10462 autocomplete: 'new-password',
10463 placeholder : this.placeholder || ''
10467 input.name = this.name;
10470 input.cls += ' input-' + this.size;
10473 if (this.disabled) {
10474 input.disabled=true;
10477 var inputblock = input;
10479 if(this.hasFeedback && !this.allowBlank){
10483 cls: 'glyphicon form-control-feedback'
10486 if(this.removable && !this.editable && !this.tickable){
10488 cls : 'has-feedback',
10494 cls : 'roo-combo-removable-btn close'
10501 cls : 'has-feedback',
10510 if(this.removable && !this.editable && !this.tickable){
10512 cls : 'roo-removable',
10518 cls : 'roo-combo-removable-btn close'
10525 if (this.before || this.after) {
10528 cls : 'input-group',
10532 inputblock.cn.push({
10534 cls : 'input-group-addon input-group-prepend input-group-text',
10539 inputblock.cn.push(input);
10541 if(this.hasFeedback && !this.allowBlank){
10542 inputblock.cls += ' has-feedback';
10543 inputblock.cn.push(feedback);
10547 inputblock.cn.push({
10549 cls : 'input-group-addon input-group-append input-group-text',
10558 var ibwrap = inputblock;
10563 cls: 'roo-select2-choices',
10567 cls: 'roo-select2-search-field',
10579 cls: 'roo-select2-container input-group',
10584 cls: 'form-hidden-field'
10590 if(!this.multiple && this.showToggleBtn){
10596 if (this.caret != false) {
10599 cls: 'fa fa-' + this.caret
10606 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10611 cls: 'combobox-clear',
10625 combobox.cls += ' roo-select2-container-multi';
10629 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10630 tooltip : 'This field is required'
10632 if (Roo.bootstrap.version == 4) {
10635 style : 'display:none'
10640 if (align ==='left' && this.fieldLabel.length) {
10642 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10649 cls : 'control-label',
10650 html : this.fieldLabel
10662 var labelCfg = cfg.cn[1];
10663 var contentCfg = cfg.cn[2];
10665 if(this.indicatorpos == 'right'){
10670 cls : 'control-label',
10674 html : this.fieldLabel
10688 labelCfg = cfg.cn[0];
10689 contentCfg = cfg.cn[1];
10692 if(this.labelWidth > 12){
10693 labelCfg.style = "width: " + this.labelWidth + 'px';
10696 if(this.labelWidth < 13 && this.labelmd == 0){
10697 this.labelmd = this.labelWidth;
10700 if(this.labellg > 0){
10701 labelCfg.cls += ' col-lg-' + this.labellg;
10702 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10705 if(this.labelmd > 0){
10706 labelCfg.cls += ' col-md-' + this.labelmd;
10707 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10710 if(this.labelsm > 0){
10711 labelCfg.cls += ' col-sm-' + this.labelsm;
10712 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10715 if(this.labelxs > 0){
10716 labelCfg.cls += ' col-xs-' + this.labelxs;
10717 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10720 } else if ( this.fieldLabel.length) {
10721 // Roo.log(" label");
10726 //cls : 'input-group-addon',
10727 html : this.fieldLabel
10735 if(this.indicatorpos == 'right'){
10743 html : this.fieldLabel
10757 // Roo.log(" no label && no align");
10764 ['xs','sm','md','lg'].map(function(size){
10765 if (settings[size]) {
10766 cfg.cls += ' col-' + size + '-' + settings[size];
10777 onResize : function(w, h){
10778 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10779 // if(typeof w == 'number'){
10780 // var x = w - this.trigger.getWidth();
10781 // this.inputEl().setWidth(this.adjustWidth('input', x));
10782 // this.trigger.setStyle('left', x+'px');
10787 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10790 getResizeEl : function(){
10791 return this.inputEl();
10795 getPositionEl : function(){
10796 return this.inputEl();
10800 alignErrorIcon : function(){
10801 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10805 initEvents : function(){
10809 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10810 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10811 if(!this.multiple && this.showToggleBtn){
10812 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10813 if(this.hideTrigger){
10814 this.trigger.setDisplayed(false);
10816 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10820 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10823 if(this.removable && !this.editable && !this.tickable){
10824 var close = this.closeTriggerEl();
10827 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10828 close.on('click', this.removeBtnClick, this, close);
10832 //this.trigger.addClassOnOver('x-form-trigger-over');
10833 //this.trigger.addClassOnClick('x-form-trigger-click');
10836 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10840 closeTriggerEl : function()
10842 var close = this.el.select('.roo-combo-removable-btn', true).first();
10843 return close ? close : false;
10846 removeBtnClick : function(e, h, el)
10848 e.preventDefault();
10850 if(this.fireEvent("remove", this) !== false){
10852 this.fireEvent("afterremove", this)
10856 createList : function()
10858 this.list = Roo.get(document.body).createChild({
10859 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10860 cls: 'typeahead typeahead-long dropdown-menu',
10861 style: 'display:none'
10864 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10869 initTrigger : function(){
10874 onDestroy : function(){
10876 this.trigger.removeAllListeners();
10877 // this.trigger.remove();
10880 // this.wrap.remove();
10882 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10886 onFocus : function(){
10887 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10889 if(!this.mimicing){
10890 this.wrap.addClass('x-trigger-wrap-focus');
10891 this.mimicing = true;
10892 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10893 if(this.monitorTab){
10894 this.el.on("keydown", this.checkTab, this);
10901 checkTab : function(e){
10902 if(e.getKey() == e.TAB){
10903 this.triggerBlur();
10908 onBlur : function(){
10913 mimicBlur : function(e, t){
10915 if(!this.wrap.contains(t) && this.validateBlur()){
10916 this.triggerBlur();
10922 triggerBlur : function(){
10923 this.mimicing = false;
10924 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10925 if(this.monitorTab){
10926 this.el.un("keydown", this.checkTab, this);
10928 //this.wrap.removeClass('x-trigger-wrap-focus');
10929 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10933 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10934 validateBlur : function(e, t){
10939 onDisable : function(){
10940 this.inputEl().dom.disabled = true;
10941 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10943 // this.wrap.addClass('x-item-disabled');
10948 onEnable : function(){
10949 this.inputEl().dom.disabled = false;
10950 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10952 // this.el.removeClass('x-item-disabled');
10957 onShow : function(){
10958 var ae = this.getActionEl();
10961 ae.dom.style.display = '';
10962 ae.dom.style.visibility = 'visible';
10968 onHide : function(){
10969 var ae = this.getActionEl();
10970 ae.dom.style.display = 'none';
10974 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10975 * by an implementing function.
10977 * @param {EventObject} e
10979 onTriggerClick : Roo.emptyFn
10983 * Ext JS Library 1.1.1
10984 * Copyright(c) 2006-2007, Ext JS, LLC.
10986 * Originally Released Under LGPL - original licence link has changed is not relivant.
10989 * <script type="text/javascript">
10994 * @class Roo.data.SortTypes
10996 * Defines the default sorting (casting?) comparison functions used when sorting data.
10998 Roo.data.SortTypes = {
11000 * Default sort that does nothing
11001 * @param {Mixed} s The value being converted
11002 * @return {Mixed} The comparison value
11004 none : function(s){
11009 * The regular expression used to strip tags
11013 stripTagsRE : /<\/?[^>]+>/gi,
11016 * Strips all HTML tags to sort on text only
11017 * @param {Mixed} s The value being converted
11018 * @return {String} The comparison value
11020 asText : function(s){
11021 return String(s).replace(this.stripTagsRE, "");
11025 * Strips all HTML tags to sort on text only - Case insensitive
11026 * @param {Mixed} s The value being converted
11027 * @return {String} The comparison value
11029 asUCText : function(s){
11030 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11034 * Case insensitive string
11035 * @param {Mixed} s The value being converted
11036 * @return {String} The comparison value
11038 asUCString : function(s) {
11039 return String(s).toUpperCase();
11044 * @param {Mixed} s The value being converted
11045 * @return {Number} The comparison value
11047 asDate : function(s) {
11051 if(s instanceof Date){
11052 return s.getTime();
11054 return Date.parse(String(s));
11059 * @param {Mixed} s The value being converted
11060 * @return {Float} The comparison value
11062 asFloat : function(s) {
11063 var val = parseFloat(String(s).replace(/,/g, ""));
11072 * @param {Mixed} s The value being converted
11073 * @return {Number} The comparison value
11075 asInt : function(s) {
11076 var val = parseInt(String(s).replace(/,/g, ""));
11084 * Ext JS Library 1.1.1
11085 * Copyright(c) 2006-2007, Ext JS, LLC.
11087 * Originally Released Under LGPL - original licence link has changed is not relivant.
11090 * <script type="text/javascript">
11094 * @class Roo.data.Record
11095 * Instances of this class encapsulate both record <em>definition</em> information, and record
11096 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11097 * to access Records cached in an {@link Roo.data.Store} object.<br>
11099 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11100 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11103 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11105 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11106 * {@link #create}. The parameters are the same.
11107 * @param {Array} data An associative Array of data values keyed by the field name.
11108 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11109 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11110 * not specified an integer id is generated.
11112 Roo.data.Record = function(data, id){
11113 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11118 * Generate a constructor for a specific record layout.
11119 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11120 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11121 * Each field definition object may contain the following properties: <ul>
11122 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
11123 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11124 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11125 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11126 * is being used, then this is a string containing the javascript expression to reference the data relative to
11127 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11128 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11129 * this may be omitted.</p></li>
11130 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11131 * <ul><li>auto (Default, implies no conversion)</li>
11136 * <li>date</li></ul></p></li>
11137 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11138 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11139 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11140 * by the Reader into an object that will be stored in the Record. It is passed the
11141 * following parameters:<ul>
11142 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11144 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11146 * <br>usage:<br><pre><code>
11147 var TopicRecord = Roo.data.Record.create(
11148 {name: 'title', mapping: 'topic_title'},
11149 {name: 'author', mapping: 'username'},
11150 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11151 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11152 {name: 'lastPoster', mapping: 'user2'},
11153 {name: 'excerpt', mapping: 'post_text'}
11156 var myNewRecord = new TopicRecord({
11157 title: 'Do my job please',
11160 lastPost: new Date(),
11161 lastPoster: 'Animal',
11162 excerpt: 'No way dude!'
11164 myStore.add(myNewRecord);
11169 Roo.data.Record.create = function(o){
11170 var f = function(){
11171 f.superclass.constructor.apply(this, arguments);
11173 Roo.extend(f, Roo.data.Record);
11174 var p = f.prototype;
11175 p.fields = new Roo.util.MixedCollection(false, function(field){
11178 for(var i = 0, len = o.length; i < len; i++){
11179 p.fields.add(new Roo.data.Field(o[i]));
11181 f.getField = function(name){
11182 return p.fields.get(name);
11187 Roo.data.Record.AUTO_ID = 1000;
11188 Roo.data.Record.EDIT = 'edit';
11189 Roo.data.Record.REJECT = 'reject';
11190 Roo.data.Record.COMMIT = 'commit';
11192 Roo.data.Record.prototype = {
11194 * Readonly flag - true if this record has been modified.
11203 join : function(store){
11204 this.store = store;
11208 * Set the named field to the specified value.
11209 * @param {String} name The name of the field to set.
11210 * @param {Object} value The value to set the field to.
11212 set : function(name, value){
11213 if(this.data[name] == value){
11217 if(!this.modified){
11218 this.modified = {};
11220 if(typeof this.modified[name] == 'undefined'){
11221 this.modified[name] = this.data[name];
11223 this.data[name] = value;
11224 if(!this.editing && this.store){
11225 this.store.afterEdit(this);
11230 * Get the value of the named field.
11231 * @param {String} name The name of the field to get the value of.
11232 * @return {Object} The value of the field.
11234 get : function(name){
11235 return this.data[name];
11239 beginEdit : function(){
11240 this.editing = true;
11241 this.modified = {};
11245 cancelEdit : function(){
11246 this.editing = false;
11247 delete this.modified;
11251 endEdit : function(){
11252 this.editing = false;
11253 if(this.dirty && this.store){
11254 this.store.afterEdit(this);
11259 * Usually called by the {@link Roo.data.Store} which owns the Record.
11260 * Rejects all changes made to the Record since either creation, or the last commit operation.
11261 * Modified fields are reverted to their original values.
11263 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11264 * of reject operations.
11266 reject : function(){
11267 var m = this.modified;
11269 if(typeof m[n] != "function"){
11270 this.data[n] = m[n];
11273 this.dirty = false;
11274 delete this.modified;
11275 this.editing = false;
11277 this.store.afterReject(this);
11282 * Usually called by the {@link Roo.data.Store} which owns the Record.
11283 * Commits all changes made to the Record since either creation, or the last commit operation.
11285 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11286 * of commit operations.
11288 commit : function(){
11289 this.dirty = false;
11290 delete this.modified;
11291 this.editing = false;
11293 this.store.afterCommit(this);
11298 hasError : function(){
11299 return this.error != null;
11303 clearError : function(){
11308 * Creates a copy of this record.
11309 * @param {String} id (optional) A new record id if you don't want to use this record's id
11312 copy : function(newId) {
11313 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11317 * Ext JS Library 1.1.1
11318 * Copyright(c) 2006-2007, Ext JS, LLC.
11320 * Originally Released Under LGPL - original licence link has changed is not relivant.
11323 * <script type="text/javascript">
11329 * @class Roo.data.Store
11330 * @extends Roo.util.Observable
11331 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11332 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11334 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
11335 * has no knowledge of the format of the data returned by the Proxy.<br>
11337 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11338 * instances from the data object. These records are cached and made available through accessor functions.
11340 * Creates a new Store.
11341 * @param {Object} config A config object containing the objects needed for the Store to access data,
11342 * and read the data into Records.
11344 Roo.data.Store = function(config){
11345 this.data = new Roo.util.MixedCollection(false);
11346 this.data.getKey = function(o){
11349 this.baseParams = {};
11351 this.paramNames = {
11356 "multisort" : "_multisort"
11359 if(config && config.data){
11360 this.inlineData = config.data;
11361 delete config.data;
11364 Roo.apply(this, config);
11366 if(this.reader){ // reader passed
11367 this.reader = Roo.factory(this.reader, Roo.data);
11368 this.reader.xmodule = this.xmodule || false;
11369 if(!this.recordType){
11370 this.recordType = this.reader.recordType;
11372 if(this.reader.onMetaChange){
11373 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11377 if(this.recordType){
11378 this.fields = this.recordType.prototype.fields;
11380 this.modified = [];
11384 * @event datachanged
11385 * Fires when the data cache has changed, and a widget which is using this Store
11386 * as a Record cache should refresh its view.
11387 * @param {Store} this
11389 datachanged : true,
11391 * @event metachange
11392 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11393 * @param {Store} this
11394 * @param {Object} meta The JSON metadata
11399 * Fires when Records have been added to the Store
11400 * @param {Store} this
11401 * @param {Roo.data.Record[]} records The array of Records added
11402 * @param {Number} index The index at which the record(s) were added
11407 * Fires when a Record has been removed from the Store
11408 * @param {Store} this
11409 * @param {Roo.data.Record} record The Record that was removed
11410 * @param {Number} index The index at which the record was removed
11415 * Fires when a Record has been updated
11416 * @param {Store} this
11417 * @param {Roo.data.Record} record The Record that was updated
11418 * @param {String} operation The update operation being performed. Value may be one of:
11420 Roo.data.Record.EDIT
11421 Roo.data.Record.REJECT
11422 Roo.data.Record.COMMIT
11428 * Fires when the data cache has been cleared.
11429 * @param {Store} this
11433 * @event beforeload
11434 * Fires before a request is made for a new data object. If the beforeload handler returns false
11435 * the load action will be canceled.
11436 * @param {Store} this
11437 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11441 * @event beforeloadadd
11442 * Fires after a new set of Records has been loaded.
11443 * @param {Store} this
11444 * @param {Roo.data.Record[]} records The Records that were loaded
11445 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11447 beforeloadadd : true,
11450 * Fires after a new set of Records has been loaded, before they are added to the store.
11451 * @param {Store} this
11452 * @param {Roo.data.Record[]} records The Records that were loaded
11453 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11454 * @params {Object} return from reader
11458 * @event loadexception
11459 * Fires if an exception occurs in the Proxy during loading.
11460 * Called with the signature of the Proxy's "loadexception" event.
11461 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11464 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11465 * @param {Object} load options
11466 * @param {Object} jsonData from your request (normally this contains the Exception)
11468 loadexception : true
11472 this.proxy = Roo.factory(this.proxy, Roo.data);
11473 this.proxy.xmodule = this.xmodule || false;
11474 this.relayEvents(this.proxy, ["loadexception"]);
11476 this.sortToggle = {};
11477 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11479 Roo.data.Store.superclass.constructor.call(this);
11481 if(this.inlineData){
11482 this.loadData(this.inlineData);
11483 delete this.inlineData;
11487 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11489 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11490 * without a remote query - used by combo/forms at present.
11494 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11497 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11500 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11501 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11504 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11505 * on any HTTP request
11508 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11511 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11515 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11516 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11518 remoteSort : false,
11521 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11522 * loaded or when a record is removed. (defaults to false).
11524 pruneModifiedRecords : false,
11527 lastOptions : null,
11530 * Add Records to the Store and fires the add event.
11531 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11533 add : function(records){
11534 records = [].concat(records);
11535 for(var i = 0, len = records.length; i < len; i++){
11536 records[i].join(this);
11538 var index = this.data.length;
11539 this.data.addAll(records);
11540 this.fireEvent("add", this, records, index);
11544 * Remove a Record from the Store and fires the remove event.
11545 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11547 remove : function(record){
11548 var index = this.data.indexOf(record);
11549 this.data.removeAt(index);
11551 if(this.pruneModifiedRecords){
11552 this.modified.remove(record);
11554 this.fireEvent("remove", this, record, index);
11558 * Remove all Records from the Store and fires the clear event.
11560 removeAll : function(){
11562 if(this.pruneModifiedRecords){
11563 this.modified = [];
11565 this.fireEvent("clear", this);
11569 * Inserts Records to the Store at the given index and fires the add event.
11570 * @param {Number} index The start index at which to insert the passed Records.
11571 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11573 insert : function(index, records){
11574 records = [].concat(records);
11575 for(var i = 0, len = records.length; i < len; i++){
11576 this.data.insert(index, records[i]);
11577 records[i].join(this);
11579 this.fireEvent("add", this, records, index);
11583 * Get the index within the cache of the passed Record.
11584 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11585 * @return {Number} The index of the passed Record. Returns -1 if not found.
11587 indexOf : function(record){
11588 return this.data.indexOf(record);
11592 * Get the index within the cache of the Record with the passed id.
11593 * @param {String} id The id of the Record to find.
11594 * @return {Number} The index of the Record. Returns -1 if not found.
11596 indexOfId : function(id){
11597 return this.data.indexOfKey(id);
11601 * Get the Record with the specified id.
11602 * @param {String} id The id of the Record to find.
11603 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11605 getById : function(id){
11606 return this.data.key(id);
11610 * Get the Record at the specified index.
11611 * @param {Number} index The index of the Record to find.
11612 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11614 getAt : function(index){
11615 return this.data.itemAt(index);
11619 * Returns a range of Records between specified indices.
11620 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11621 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11622 * @return {Roo.data.Record[]} An array of Records
11624 getRange : function(start, end){
11625 return this.data.getRange(start, end);
11629 storeOptions : function(o){
11630 o = Roo.apply({}, o);
11633 this.lastOptions = o;
11637 * Loads the Record cache from the configured Proxy using the configured Reader.
11639 * If using remote paging, then the first load call must specify the <em>start</em>
11640 * and <em>limit</em> properties in the options.params property to establish the initial
11641 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11643 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11644 * and this call will return before the new data has been loaded. Perform any post-processing
11645 * in a callback function, or in a "load" event handler.</strong>
11647 * @param {Object} options An object containing properties which control loading options:<ul>
11648 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11649 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11650 * passed the following arguments:<ul>
11651 * <li>r : Roo.data.Record[]</li>
11652 * <li>options: Options object from the load call</li>
11653 * <li>success: Boolean success indicator</li></ul></li>
11654 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11655 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11658 load : function(options){
11659 options = options || {};
11660 if(this.fireEvent("beforeload", this, options) !== false){
11661 this.storeOptions(options);
11662 var p = Roo.apply(options.params || {}, this.baseParams);
11663 // if meta was not loaded from remote source.. try requesting it.
11664 if (!this.reader.metaFromRemote) {
11665 p._requestMeta = 1;
11667 if(this.sortInfo && this.remoteSort){
11668 var pn = this.paramNames;
11669 p[pn["sort"]] = this.sortInfo.field;
11670 p[pn["dir"]] = this.sortInfo.direction;
11672 if (this.multiSort) {
11673 var pn = this.paramNames;
11674 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11677 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11682 * Reloads the Record cache from the configured Proxy using the configured Reader and
11683 * the options from the last load operation performed.
11684 * @param {Object} options (optional) An object containing properties which may override the options
11685 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11686 * the most recently used options are reused).
11688 reload : function(options){
11689 this.load(Roo.applyIf(options||{}, this.lastOptions));
11693 // Called as a callback by the Reader during a load operation.
11694 loadRecords : function(o, options, success){
11695 if(!o || success === false){
11696 if(success !== false){
11697 this.fireEvent("load", this, [], options, o);
11699 if(options.callback){
11700 options.callback.call(options.scope || this, [], options, false);
11704 // if data returned failure - throw an exception.
11705 if (o.success === false) {
11706 // show a message if no listener is registered.
11707 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11708 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11710 // loadmask wil be hooked into this..
11711 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11714 var r = o.records, t = o.totalRecords || r.length;
11716 this.fireEvent("beforeloadadd", this, r, options, o);
11718 if(!options || options.add !== true){
11719 if(this.pruneModifiedRecords){
11720 this.modified = [];
11722 for(var i = 0, len = r.length; i < len; i++){
11726 this.data = this.snapshot;
11727 delete this.snapshot;
11730 this.data.addAll(r);
11731 this.totalLength = t;
11733 this.fireEvent("datachanged", this);
11735 this.totalLength = Math.max(t, this.data.length+r.length);
11739 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11741 var e = new Roo.data.Record({});
11743 e.set(this.parent.displayField, this.parent.emptyTitle);
11744 e.set(this.parent.valueField, '');
11749 this.fireEvent("load", this, r, options, o);
11750 if(options.callback){
11751 options.callback.call(options.scope || this, r, options, true);
11757 * Loads data from a passed data block. A Reader which understands the format of the data
11758 * must have been configured in the constructor.
11759 * @param {Object} data The data block from which to read the Records. The format of the data expected
11760 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11761 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11763 loadData : function(o, append){
11764 var r = this.reader.readRecords(o);
11765 this.loadRecords(r, {add: append}, true);
11769 * Gets the number of cached records.
11771 * <em>If using paging, this may not be the total size of the dataset. If the data object
11772 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11773 * the data set size</em>
11775 getCount : function(){
11776 return this.data.length || 0;
11780 * Gets the total number of records in the dataset as returned by the server.
11782 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11783 * the dataset size</em>
11785 getTotalCount : function(){
11786 return this.totalLength || 0;
11790 * Returns the sort state of the Store as an object with two properties:
11792 field {String} The name of the field by which the Records are sorted
11793 direction {String} The sort order, "ASC" or "DESC"
11796 getSortState : function(){
11797 return this.sortInfo;
11801 applySort : function(){
11802 if(this.sortInfo && !this.remoteSort){
11803 var s = this.sortInfo, f = s.field;
11804 var st = this.fields.get(f).sortType;
11805 var fn = function(r1, r2){
11806 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11807 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11809 this.data.sort(s.direction, fn);
11810 if(this.snapshot && this.snapshot != this.data){
11811 this.snapshot.sort(s.direction, fn);
11817 * Sets the default sort column and order to be used by the next load operation.
11818 * @param {String} fieldName The name of the field to sort by.
11819 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11821 setDefaultSort : function(field, dir){
11822 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11826 * Sort the Records.
11827 * If remote sorting is used, the sort is performed on the server, and the cache is
11828 * reloaded. If local sorting is used, the cache is sorted internally.
11829 * @param {String} fieldName The name of the field to sort by.
11830 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11832 sort : function(fieldName, dir){
11833 var f = this.fields.get(fieldName);
11835 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11837 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11838 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11843 this.sortToggle[f.name] = dir;
11844 this.sortInfo = {field: f.name, direction: dir};
11845 if(!this.remoteSort){
11847 this.fireEvent("datachanged", this);
11849 this.load(this.lastOptions);
11854 * Calls the specified function for each of the Records in the cache.
11855 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11856 * Returning <em>false</em> aborts and exits the iteration.
11857 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11859 each : function(fn, scope){
11860 this.data.each(fn, scope);
11864 * Gets all records modified since the last commit. Modified records are persisted across load operations
11865 * (e.g., during paging).
11866 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11868 getModifiedRecords : function(){
11869 return this.modified;
11873 createFilterFn : function(property, value, anyMatch){
11874 if(!value.exec){ // not a regex
11875 value = String(value);
11876 if(value.length == 0){
11879 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11881 return function(r){
11882 return value.test(r.data[property]);
11887 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11888 * @param {String} property A field on your records
11889 * @param {Number} start The record index to start at (defaults to 0)
11890 * @param {Number} end The last record index to include (defaults to length - 1)
11891 * @return {Number} The sum
11893 sum : function(property, start, end){
11894 var rs = this.data.items, v = 0;
11895 start = start || 0;
11896 end = (end || end === 0) ? end : rs.length-1;
11898 for(var i = start; i <= end; i++){
11899 v += (rs[i].data[property] || 0);
11905 * Filter the records by a specified property.
11906 * @param {String} field A field on your records
11907 * @param {String/RegExp} value Either a string that the field
11908 * should start with or a RegExp to test against the field
11909 * @param {Boolean} anyMatch True to match any part not just the beginning
11911 filter : function(property, value, anyMatch){
11912 var fn = this.createFilterFn(property, value, anyMatch);
11913 return fn ? this.filterBy(fn) : this.clearFilter();
11917 * Filter by a function. The specified function will be called with each
11918 * record in this data source. If the function returns true the record is included,
11919 * otherwise it is filtered.
11920 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11921 * @param {Object} scope (optional) The scope of the function (defaults to this)
11923 filterBy : function(fn, scope){
11924 this.snapshot = this.snapshot || this.data;
11925 this.data = this.queryBy(fn, scope||this);
11926 this.fireEvent("datachanged", this);
11930 * Query the records by a specified property.
11931 * @param {String} field A field on your records
11932 * @param {String/RegExp} value Either a string that the field
11933 * should start with or a RegExp to test against the field
11934 * @param {Boolean} anyMatch True to match any part not just the beginning
11935 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11937 query : function(property, value, anyMatch){
11938 var fn = this.createFilterFn(property, value, anyMatch);
11939 return fn ? this.queryBy(fn) : this.data.clone();
11943 * Query by a function. The specified function will be called with each
11944 * record in this data source. If the function returns true the record is included
11946 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11947 * @param {Object} scope (optional) The scope of the function (defaults to this)
11948 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11950 queryBy : function(fn, scope){
11951 var data = this.snapshot || this.data;
11952 return data.filterBy(fn, scope||this);
11956 * Collects unique values for a particular dataIndex from this store.
11957 * @param {String} dataIndex The property to collect
11958 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11959 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11960 * @return {Array} An array of the unique values
11962 collect : function(dataIndex, allowNull, bypassFilter){
11963 var d = (bypassFilter === true && this.snapshot) ?
11964 this.snapshot.items : this.data.items;
11965 var v, sv, r = [], l = {};
11966 for(var i = 0, len = d.length; i < len; i++){
11967 v = d[i].data[dataIndex];
11969 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11978 * Revert to a view of the Record cache with no filtering applied.
11979 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11981 clearFilter : function(suppressEvent){
11982 if(this.snapshot && this.snapshot != this.data){
11983 this.data = this.snapshot;
11984 delete this.snapshot;
11985 if(suppressEvent !== true){
11986 this.fireEvent("datachanged", this);
11992 afterEdit : function(record){
11993 if(this.modified.indexOf(record) == -1){
11994 this.modified.push(record);
11996 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12000 afterReject : function(record){
12001 this.modified.remove(record);
12002 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12006 afterCommit : function(record){
12007 this.modified.remove(record);
12008 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12012 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12013 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12015 commitChanges : function(){
12016 var m = this.modified.slice(0);
12017 this.modified = [];
12018 for(var i = 0, len = m.length; i < len; i++){
12024 * Cancel outstanding changes on all changed records.
12026 rejectChanges : function(){
12027 var m = this.modified.slice(0);
12028 this.modified = [];
12029 for(var i = 0, len = m.length; i < len; i++){
12034 onMetaChange : function(meta, rtype, o){
12035 this.recordType = rtype;
12036 this.fields = rtype.prototype.fields;
12037 delete this.snapshot;
12038 this.sortInfo = meta.sortInfo || this.sortInfo;
12039 this.modified = [];
12040 this.fireEvent('metachange', this, this.reader.meta);
12043 moveIndex : function(data, type)
12045 var index = this.indexOf(data);
12047 var newIndex = index + type;
12051 this.insert(newIndex, data);
12056 * Ext JS Library 1.1.1
12057 * Copyright(c) 2006-2007, Ext JS, LLC.
12059 * Originally Released Under LGPL - original licence link has changed is not relivant.
12062 * <script type="text/javascript">
12066 * @class Roo.data.SimpleStore
12067 * @extends Roo.data.Store
12068 * Small helper class to make creating Stores from Array data easier.
12069 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12070 * @cfg {Array} fields An array of field definition objects, or field name strings.
12071 * @cfg {Array} data The multi-dimensional array of data
12073 * @param {Object} config
12075 Roo.data.SimpleStore = function(config){
12076 Roo.data.SimpleStore.superclass.constructor.call(this, {
12078 reader: new Roo.data.ArrayReader({
12081 Roo.data.Record.create(config.fields)
12083 proxy : new Roo.data.MemoryProxy(config.data)
12087 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12089 * Ext JS Library 1.1.1
12090 * Copyright(c) 2006-2007, Ext JS, LLC.
12092 * Originally Released Under LGPL - original licence link has changed is not relivant.
12095 * <script type="text/javascript">
12100 * @extends Roo.data.Store
12101 * @class Roo.data.JsonStore
12102 * Small helper class to make creating Stores for JSON data easier. <br/>
12104 var store = new Roo.data.JsonStore({
12105 url: 'get-images.php',
12107 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12110 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12111 * JsonReader and HttpProxy (unless inline data is provided).</b>
12112 * @cfg {Array} fields An array of field definition objects, or field name strings.
12114 * @param {Object} config
12116 Roo.data.JsonStore = function(c){
12117 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12118 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12119 reader: new Roo.data.JsonReader(c, c.fields)
12122 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12124 * Ext JS Library 1.1.1
12125 * Copyright(c) 2006-2007, Ext JS, LLC.
12127 * Originally Released Under LGPL - original licence link has changed is not relivant.
12130 * <script type="text/javascript">
12134 Roo.data.Field = function(config){
12135 if(typeof config == "string"){
12136 config = {name: config};
12138 Roo.apply(this, config);
12141 this.type = "auto";
12144 var st = Roo.data.SortTypes;
12145 // named sortTypes are supported, here we look them up
12146 if(typeof this.sortType == "string"){
12147 this.sortType = st[this.sortType];
12150 // set default sortType for strings and dates
12151 if(!this.sortType){
12154 this.sortType = st.asUCString;
12157 this.sortType = st.asDate;
12160 this.sortType = st.none;
12165 var stripRe = /[\$,%]/g;
12167 // prebuilt conversion function for this field, instead of
12168 // switching every time we're reading a value
12170 var cv, dateFormat = this.dateFormat;
12175 cv = function(v){ return v; };
12178 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12182 return v !== undefined && v !== null && v !== '' ?
12183 parseInt(String(v).replace(stripRe, ""), 10) : '';
12188 return v !== undefined && v !== null && v !== '' ?
12189 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12194 cv = function(v){ return v === true || v === "true" || v == 1; };
12201 if(v instanceof Date){
12205 if(dateFormat == "timestamp"){
12206 return new Date(v*1000);
12208 return Date.parseDate(v, dateFormat);
12210 var parsed = Date.parse(v);
12211 return parsed ? new Date(parsed) : null;
12220 Roo.data.Field.prototype = {
12228 * Ext JS Library 1.1.1
12229 * Copyright(c) 2006-2007, Ext JS, LLC.
12231 * Originally Released Under LGPL - original licence link has changed is not relivant.
12234 * <script type="text/javascript">
12237 // Base class for reading structured data from a data source. This class is intended to be
12238 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12241 * @class Roo.data.DataReader
12242 * Base class for reading structured data from a data source. This class is intended to be
12243 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12246 Roo.data.DataReader = function(meta, recordType){
12250 this.recordType = recordType instanceof Array ?
12251 Roo.data.Record.create(recordType) : recordType;
12254 Roo.data.DataReader.prototype = {
12256 * Create an empty record
12257 * @param {Object} data (optional) - overlay some values
12258 * @return {Roo.data.Record} record created.
12260 newRow : function(d) {
12262 this.recordType.prototype.fields.each(function(c) {
12264 case 'int' : da[c.name] = 0; break;
12265 case 'date' : da[c.name] = new Date(); break;
12266 case 'float' : da[c.name] = 0.0; break;
12267 case 'boolean' : da[c.name] = false; break;
12268 default : da[c.name] = ""; break;
12272 return new this.recordType(Roo.apply(da, d));
12277 * Ext JS Library 1.1.1
12278 * Copyright(c) 2006-2007, Ext JS, LLC.
12280 * Originally Released Under LGPL - original licence link has changed is not relivant.
12283 * <script type="text/javascript">
12287 * @class Roo.data.DataProxy
12288 * @extends Roo.data.Observable
12289 * This class is an abstract base class for implementations which provide retrieval of
12290 * unformatted data objects.<br>
12292 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12293 * (of the appropriate type which knows how to parse the data object) to provide a block of
12294 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12296 * Custom implementations must implement the load method as described in
12297 * {@link Roo.data.HttpProxy#load}.
12299 Roo.data.DataProxy = function(){
12302 * @event beforeload
12303 * Fires before a network request is made to retrieve a data object.
12304 * @param {Object} This DataProxy object.
12305 * @param {Object} params The params parameter to the load function.
12310 * Fires before the load method's callback is called.
12311 * @param {Object} This DataProxy object.
12312 * @param {Object} o The data object.
12313 * @param {Object} arg The callback argument object passed to the load function.
12317 * @event loadexception
12318 * Fires if an Exception occurs during data retrieval.
12319 * @param {Object} This DataProxy object.
12320 * @param {Object} o The data object.
12321 * @param {Object} arg The callback argument object passed to the load function.
12322 * @param {Object} e The Exception.
12324 loadexception : true
12326 Roo.data.DataProxy.superclass.constructor.call(this);
12329 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12332 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12336 * Ext JS Library 1.1.1
12337 * Copyright(c) 2006-2007, Ext JS, LLC.
12339 * Originally Released Under LGPL - original licence link has changed is not relivant.
12342 * <script type="text/javascript">
12345 * @class Roo.data.MemoryProxy
12346 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12347 * to the Reader when its load method is called.
12349 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12351 Roo.data.MemoryProxy = function(data){
12355 Roo.data.MemoryProxy.superclass.constructor.call(this);
12359 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12362 * Load data from the requested source (in this case an in-memory
12363 * data object passed to the constructor), read the data object into
12364 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12365 * process that block using the passed callback.
12366 * @param {Object} params This parameter is not used by the MemoryProxy class.
12367 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12368 * object into a block of Roo.data.Records.
12369 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12370 * The function must be passed <ul>
12371 * <li>The Record block object</li>
12372 * <li>The "arg" argument from the load function</li>
12373 * <li>A boolean success indicator</li>
12375 * @param {Object} scope The scope in which to call the callback
12376 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12378 load : function(params, reader, callback, scope, arg){
12379 params = params || {};
12382 result = reader.readRecords(this.data);
12384 this.fireEvent("loadexception", this, arg, null, e);
12385 callback.call(scope, null, arg, false);
12388 callback.call(scope, result, arg, true);
12392 update : function(params, records){
12397 * Ext JS Library 1.1.1
12398 * Copyright(c) 2006-2007, Ext JS, LLC.
12400 * Originally Released Under LGPL - original licence link has changed is not relivant.
12403 * <script type="text/javascript">
12406 * @class Roo.data.HttpProxy
12407 * @extends Roo.data.DataProxy
12408 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12409 * configured to reference a certain URL.<br><br>
12411 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12412 * from which the running page was served.<br><br>
12414 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12416 * Be aware that to enable the browser to parse an XML document, the server must set
12417 * the Content-Type header in the HTTP response to "text/xml".
12419 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12420 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12421 * will be used to make the request.
12423 Roo.data.HttpProxy = function(conn){
12424 Roo.data.HttpProxy.superclass.constructor.call(this);
12425 // is conn a conn config or a real conn?
12427 this.useAjax = !conn || !conn.events;
12431 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12432 // thse are take from connection...
12435 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12438 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12439 * extra parameters to each request made by this object. (defaults to undefined)
12442 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12443 * to each request made by this object. (defaults to undefined)
12446 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
12449 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12452 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12458 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12462 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12463 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12464 * a finer-grained basis than the DataProxy events.
12466 getConnection : function(){
12467 return this.useAjax ? Roo.Ajax : this.conn;
12471 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12472 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12473 * process that block using the passed callback.
12474 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12475 * for the request to the remote server.
12476 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12477 * object into a block of Roo.data.Records.
12478 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12479 * The function must be passed <ul>
12480 * <li>The Record block object</li>
12481 * <li>The "arg" argument from the load function</li>
12482 * <li>A boolean success indicator</li>
12484 * @param {Object} scope The scope in which to call the callback
12485 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12487 load : function(params, reader, callback, scope, arg){
12488 if(this.fireEvent("beforeload", this, params) !== false){
12490 params : params || {},
12492 callback : callback,
12497 callback : this.loadResponse,
12501 Roo.applyIf(o, this.conn);
12502 if(this.activeRequest){
12503 Roo.Ajax.abort(this.activeRequest);
12505 this.activeRequest = Roo.Ajax.request(o);
12507 this.conn.request(o);
12510 callback.call(scope||this, null, arg, false);
12515 loadResponse : function(o, success, response){
12516 delete this.activeRequest;
12518 this.fireEvent("loadexception", this, o, response);
12519 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12524 result = o.reader.read(response);
12526 this.fireEvent("loadexception", this, o, response, e);
12527 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12531 this.fireEvent("load", this, o, o.request.arg);
12532 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12536 update : function(dataSet){
12541 updateResponse : function(dataSet){
12546 * Ext JS Library 1.1.1
12547 * Copyright(c) 2006-2007, Ext JS, LLC.
12549 * Originally Released Under LGPL - original licence link has changed is not relivant.
12552 * <script type="text/javascript">
12556 * @class Roo.data.ScriptTagProxy
12557 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12558 * other than the originating domain of the running page.<br><br>
12560 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
12561 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12563 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12564 * source code that is used as the source inside a <script> tag.<br><br>
12566 * In order for the browser to process the returned data, the server must wrap the data object
12567 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12568 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12569 * depending on whether the callback name was passed:
12572 boolean scriptTag = false;
12573 String cb = request.getParameter("callback");
12576 response.setContentType("text/javascript");
12578 response.setContentType("application/x-json");
12580 Writer out = response.getWriter();
12582 out.write(cb + "(");
12584 out.print(dataBlock.toJsonString());
12591 * @param {Object} config A configuration object.
12593 Roo.data.ScriptTagProxy = function(config){
12594 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12595 Roo.apply(this, config);
12596 this.head = document.getElementsByTagName("head")[0];
12599 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12601 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12603 * @cfg {String} url The URL from which to request the data object.
12606 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12610 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12611 * the server the name of the callback function set up by the load call to process the returned data object.
12612 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12613 * javascript output which calls this named function passing the data object as its only parameter.
12615 callbackParam : "callback",
12617 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12618 * name to the request.
12623 * Load data from the configured URL, read the data object into
12624 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12625 * process that block using the passed callback.
12626 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12627 * for the request to the remote server.
12628 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12629 * object into a block of Roo.data.Records.
12630 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12631 * The function must be passed <ul>
12632 * <li>The Record block object</li>
12633 * <li>The "arg" argument from the load function</li>
12634 * <li>A boolean success indicator</li>
12636 * @param {Object} scope The scope in which to call the callback
12637 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12639 load : function(params, reader, callback, scope, arg){
12640 if(this.fireEvent("beforeload", this, params) !== false){
12642 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12644 var url = this.url;
12645 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12647 url += "&_dc=" + (new Date().getTime());
12649 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12652 cb : "stcCallback"+transId,
12653 scriptId : "stcScript"+transId,
12657 callback : callback,
12663 window[trans.cb] = function(o){
12664 conn.handleResponse(o, trans);
12667 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12669 if(this.autoAbort !== false){
12673 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12675 var script = document.createElement("script");
12676 script.setAttribute("src", url);
12677 script.setAttribute("type", "text/javascript");
12678 script.setAttribute("id", trans.scriptId);
12679 this.head.appendChild(script);
12681 this.trans = trans;
12683 callback.call(scope||this, null, arg, false);
12688 isLoading : function(){
12689 return this.trans ? true : false;
12693 * Abort the current server request.
12695 abort : function(){
12696 if(this.isLoading()){
12697 this.destroyTrans(this.trans);
12702 destroyTrans : function(trans, isLoaded){
12703 this.head.removeChild(document.getElementById(trans.scriptId));
12704 clearTimeout(trans.timeoutId);
12706 window[trans.cb] = undefined;
12708 delete window[trans.cb];
12711 // if hasn't been loaded, wait for load to remove it to prevent script error
12712 window[trans.cb] = function(){
12713 window[trans.cb] = undefined;
12715 delete window[trans.cb];
12722 handleResponse : function(o, trans){
12723 this.trans = false;
12724 this.destroyTrans(trans, true);
12727 result = trans.reader.readRecords(o);
12729 this.fireEvent("loadexception", this, o, trans.arg, e);
12730 trans.callback.call(trans.scope||window, null, trans.arg, false);
12733 this.fireEvent("load", this, o, trans.arg);
12734 trans.callback.call(trans.scope||window, result, trans.arg, true);
12738 handleFailure : function(trans){
12739 this.trans = false;
12740 this.destroyTrans(trans, false);
12741 this.fireEvent("loadexception", this, null, trans.arg);
12742 trans.callback.call(trans.scope||window, null, trans.arg, false);
12746 * Ext JS Library 1.1.1
12747 * Copyright(c) 2006-2007, Ext JS, LLC.
12749 * Originally Released Under LGPL - original licence link has changed is not relivant.
12752 * <script type="text/javascript">
12756 * @class Roo.data.JsonReader
12757 * @extends Roo.data.DataReader
12758 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12759 * based on mappings in a provided Roo.data.Record constructor.
12761 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12762 * in the reply previously.
12767 var RecordDef = Roo.data.Record.create([
12768 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12769 {name: 'occupation'} // This field will use "occupation" as the mapping.
12771 var myReader = new Roo.data.JsonReader({
12772 totalProperty: "results", // The property which contains the total dataset size (optional)
12773 root: "rows", // The property which contains an Array of row objects
12774 id: "id" // The property within each row object that provides an ID for the record (optional)
12778 * This would consume a JSON file like this:
12780 { 'results': 2, 'rows': [
12781 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12782 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12785 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12786 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12787 * paged from the remote server.
12788 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12789 * @cfg {String} root name of the property which contains the Array of row objects.
12790 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12791 * @cfg {Array} fields Array of field definition objects
12793 * Create a new JsonReader
12794 * @param {Object} meta Metadata configuration options
12795 * @param {Object} recordType Either an Array of field definition objects,
12796 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12798 Roo.data.JsonReader = function(meta, recordType){
12801 // set some defaults:
12802 Roo.applyIf(meta, {
12803 totalProperty: 'total',
12804 successProperty : 'success',
12809 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12811 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12814 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12815 * Used by Store query builder to append _requestMeta to params.
12818 metaFromRemote : false,
12820 * This method is only used by a DataProxy which has retrieved data from a remote server.
12821 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12822 * @return {Object} data A data block which is used by an Roo.data.Store object as
12823 * a cache of Roo.data.Records.
12825 read : function(response){
12826 var json = response.responseText;
12828 var o = /* eval:var:o */ eval("("+json+")");
12830 throw {message: "JsonReader.read: Json object not found"};
12836 this.metaFromRemote = true;
12837 this.meta = o.metaData;
12838 this.recordType = Roo.data.Record.create(o.metaData.fields);
12839 this.onMetaChange(this.meta, this.recordType, o);
12841 return this.readRecords(o);
12844 // private function a store will implement
12845 onMetaChange : function(meta, recordType, o){
12852 simpleAccess: function(obj, subsc) {
12859 getJsonAccessor: function(){
12861 return function(expr) {
12863 return(re.test(expr))
12864 ? new Function("obj", "return obj." + expr)
12869 return Roo.emptyFn;
12874 * Create a data block containing Roo.data.Records from an XML document.
12875 * @param {Object} o An object which contains an Array of row objects in the property specified
12876 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12877 * which contains the total size of the dataset.
12878 * @return {Object} data A data block which is used by an Roo.data.Store object as
12879 * a cache of Roo.data.Records.
12881 readRecords : function(o){
12883 * After any data loads, the raw JSON data is available for further custom processing.
12887 var s = this.meta, Record = this.recordType,
12888 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12890 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12892 if(s.totalProperty) {
12893 this.getTotal = this.getJsonAccessor(s.totalProperty);
12895 if(s.successProperty) {
12896 this.getSuccess = this.getJsonAccessor(s.successProperty);
12898 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12900 var g = this.getJsonAccessor(s.id);
12901 this.getId = function(rec) {
12903 return (r === undefined || r === "") ? null : r;
12906 this.getId = function(){return null;};
12909 for(var jj = 0; jj < fl; jj++){
12911 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12912 this.ef[jj] = this.getJsonAccessor(map);
12916 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12917 if(s.totalProperty){
12918 var vt = parseInt(this.getTotal(o), 10);
12923 if(s.successProperty){
12924 var vs = this.getSuccess(o);
12925 if(vs === false || vs === 'false'){
12930 for(var i = 0; i < c; i++){
12933 var id = this.getId(n);
12934 for(var j = 0; j < fl; j++){
12936 var v = this.ef[j](n);
12938 Roo.log('missing convert for ' + f.name);
12942 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12944 var record = new Record(values, id);
12946 records[i] = record;
12952 totalRecords : totalRecords
12957 * Ext JS Library 1.1.1
12958 * Copyright(c) 2006-2007, Ext JS, LLC.
12960 * Originally Released Under LGPL - original licence link has changed is not relivant.
12963 * <script type="text/javascript">
12967 * @class Roo.data.ArrayReader
12968 * @extends Roo.data.DataReader
12969 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12970 * Each element of that Array represents a row of data fields. The
12971 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12972 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12976 var RecordDef = Roo.data.Record.create([
12977 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12978 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12980 var myReader = new Roo.data.ArrayReader({
12981 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12985 * This would consume an Array like this:
12987 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12989 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12991 * Create a new JsonReader
12992 * @param {Object} meta Metadata configuration options.
12993 * @param {Object} recordType Either an Array of field definition objects
12994 * as specified to {@link Roo.data.Record#create},
12995 * or an {@link Roo.data.Record} object
12996 * created using {@link Roo.data.Record#create}.
12998 Roo.data.ArrayReader = function(meta, recordType){
12999 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
13002 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13004 * Create a data block containing Roo.data.Records from an XML document.
13005 * @param {Object} o An Array of row objects which represents the dataset.
13006 * @return {Object} data A data block which is used by an Roo.data.Store object as
13007 * a cache of Roo.data.Records.
13009 readRecords : function(o){
13010 var sid = this.meta ? this.meta.id : null;
13011 var recordType = this.recordType, fields = recordType.prototype.fields;
13014 for(var i = 0; i < root.length; i++){
13017 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13018 for(var j = 0, jlen = fields.length; j < jlen; j++){
13019 var f = fields.items[j];
13020 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13021 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13023 values[f.name] = v;
13025 var record = new recordType(values, id);
13027 records[records.length] = record;
13031 totalRecords : records.length
13040 * @class Roo.bootstrap.ComboBox
13041 * @extends Roo.bootstrap.TriggerField
13042 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13043 * @cfg {Boolean} append (true|false) default false
13044 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13045 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13046 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13047 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13048 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13049 * @cfg {Boolean} animate default true
13050 * @cfg {Boolean} emptyResultText only for touch device
13051 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13052 * @cfg {String} emptyTitle default ''
13054 * Create a new ComboBox.
13055 * @param {Object} config Configuration options
13057 Roo.bootstrap.ComboBox = function(config){
13058 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13062 * Fires when the dropdown list is expanded
13063 * @param {Roo.bootstrap.ComboBox} combo This combo box
13068 * Fires when the dropdown list is collapsed
13069 * @param {Roo.bootstrap.ComboBox} combo This combo box
13073 * @event beforeselect
13074 * Fires before a list item is selected. Return false to cancel the selection.
13075 * @param {Roo.bootstrap.ComboBox} combo This combo box
13076 * @param {Roo.data.Record} record The data record returned from the underlying store
13077 * @param {Number} index The index of the selected item in the dropdown list
13079 'beforeselect' : true,
13082 * Fires when a list item is selected
13083 * @param {Roo.bootstrap.ComboBox} combo This combo box
13084 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13085 * @param {Number} index The index of the selected item in the dropdown list
13089 * @event beforequery
13090 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13091 * The event object passed has these properties:
13092 * @param {Roo.bootstrap.ComboBox} combo This combo box
13093 * @param {String} query The query
13094 * @param {Boolean} forceAll true to force "all" query
13095 * @param {Boolean} cancel true to cancel the query
13096 * @param {Object} e The query event object
13098 'beforequery': true,
13101 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13102 * @param {Roo.bootstrap.ComboBox} combo This combo box
13107 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13108 * @param {Roo.bootstrap.ComboBox} combo This combo box
13109 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13114 * Fires when the remove value from the combobox array
13115 * @param {Roo.bootstrap.ComboBox} combo This combo box
13119 * @event afterremove
13120 * Fires when the remove value from the combobox array
13121 * @param {Roo.bootstrap.ComboBox} combo This combo box
13123 'afterremove' : true,
13125 * @event specialfilter
13126 * Fires when specialfilter
13127 * @param {Roo.bootstrap.ComboBox} combo This combo box
13129 'specialfilter' : true,
13132 * Fires when tick the element
13133 * @param {Roo.bootstrap.ComboBox} combo This combo box
13137 * @event touchviewdisplay
13138 * Fires when touch view require special display (default is using displayField)
13139 * @param {Roo.bootstrap.ComboBox} combo This combo box
13140 * @param {Object} cfg set html .
13142 'touchviewdisplay' : true
13147 this.tickItems = [];
13149 this.selectedIndex = -1;
13150 if(this.mode == 'local'){
13151 if(config.queryDelay === undefined){
13152 this.queryDelay = 10;
13154 if(config.minChars === undefined){
13160 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13163 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13164 * rendering into an Roo.Editor, defaults to false)
13167 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13168 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13171 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13174 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13175 * the dropdown list (defaults to undefined, with no header element)
13179 * @cfg {String/Roo.Template} tpl The template to use to render the output
13183 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13185 listWidth: undefined,
13187 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13188 * mode = 'remote' or 'text' if mode = 'local')
13190 displayField: undefined,
13193 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13194 * mode = 'remote' or 'value' if mode = 'local').
13195 * Note: use of a valueField requires the user make a selection
13196 * in order for a value to be mapped.
13198 valueField: undefined,
13200 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13205 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13206 * field's data value (defaults to the underlying DOM element's name)
13208 hiddenName: undefined,
13210 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13214 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13216 selectedClass: 'active',
13219 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13223 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13224 * anchor positions (defaults to 'tl-bl')
13226 listAlign: 'tl-bl?',
13228 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13232 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13233 * query specified by the allQuery config option (defaults to 'query')
13235 triggerAction: 'query',
13237 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13238 * (defaults to 4, does not apply if editable = false)
13242 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13243 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13247 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13248 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13252 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13253 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13257 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13258 * when editable = true (defaults to false)
13260 selectOnFocus:false,
13262 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13264 queryParam: 'query',
13266 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13267 * when mode = 'remote' (defaults to 'Loading...')
13269 loadingText: 'Loading...',
13271 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13275 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13279 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13280 * traditional select (defaults to true)
13284 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13288 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13292 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13293 * listWidth has a higher value)
13297 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13298 * allow the user to set arbitrary text into the field (defaults to false)
13300 forceSelection:false,
13302 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13303 * if typeAhead = true (defaults to 250)
13305 typeAheadDelay : 250,
13307 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13308 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13310 valueNotFoundText : undefined,
13312 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13314 blockFocus : false,
13317 * @cfg {Boolean} disableClear Disable showing of clear button.
13319 disableClear : false,
13321 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13323 alwaysQuery : false,
13326 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13331 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13333 invalidClass : "has-warning",
13336 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13338 validClass : "has-success",
13341 * @cfg {Boolean} specialFilter (true|false) special filter default false
13343 specialFilter : false,
13346 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13348 mobileTouchView : true,
13351 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13353 useNativeIOS : false,
13356 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13358 mobile_restrict_height : false,
13360 ios_options : false,
13372 btnPosition : 'right',
13373 triggerList : true,
13374 showToggleBtn : true,
13376 emptyResultText: 'Empty',
13377 triggerText : 'Select',
13380 // element that contains real text value.. (when hidden is used..)
13382 getAutoCreate : function()
13387 * Render classic select for iso
13390 if(Roo.isIOS && this.useNativeIOS){
13391 cfg = this.getAutoCreateNativeIOS();
13399 if(Roo.isTouch && this.mobileTouchView){
13400 cfg = this.getAutoCreateTouchView();
13407 if(!this.tickable){
13408 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13413 * ComboBox with tickable selections
13416 var align = this.labelAlign || this.parentLabelAlign();
13419 cls : 'form-group roo-combobox-tickable' //input-group
13422 var btn_text_select = '';
13423 var btn_text_done = '';
13424 var btn_text_cancel = '';
13426 if (this.btn_text_show) {
13427 btn_text_select = 'Select';
13428 btn_text_done = 'Done';
13429 btn_text_cancel = 'Cancel';
13434 cls : 'tickable-buttons',
13439 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13440 //html : this.triggerText
13441 html: btn_text_select
13447 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13449 html: btn_text_done
13455 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13457 html: btn_text_cancel
13463 buttons.cn.unshift({
13465 cls: 'roo-select2-search-field-input'
13471 Roo.each(buttons.cn, function(c){
13473 c.cls += ' btn-' + _this.size;
13476 if (_this.disabled) {
13483 style : 'display: contents',
13488 cls: 'form-hidden-field'
13492 cls: 'roo-select2-choices',
13496 cls: 'roo-select2-search-field',
13507 cls: 'roo-select2-container input-group roo-select2-container-multi',
13513 // cls: 'typeahead typeahead-long dropdown-menu',
13514 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13519 if(this.hasFeedback && !this.allowBlank){
13523 cls: 'glyphicon form-control-feedback'
13526 combobox.cn.push(feedback);
13531 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13532 tooltip : 'This field is required'
13534 if (Roo.bootstrap.version == 4) {
13537 style : 'display:none'
13540 if (align ==='left' && this.fieldLabel.length) {
13542 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13549 cls : 'control-label col-form-label',
13550 html : this.fieldLabel
13562 var labelCfg = cfg.cn[1];
13563 var contentCfg = cfg.cn[2];
13566 if(this.indicatorpos == 'right'){
13572 cls : 'control-label col-form-label',
13576 html : this.fieldLabel
13592 labelCfg = cfg.cn[0];
13593 contentCfg = cfg.cn[1];
13597 if(this.labelWidth > 12){
13598 labelCfg.style = "width: " + this.labelWidth + 'px';
13601 if(this.labelWidth < 13 && this.labelmd == 0){
13602 this.labelmd = this.labelWidth;
13605 if(this.labellg > 0){
13606 labelCfg.cls += ' col-lg-' + this.labellg;
13607 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13610 if(this.labelmd > 0){
13611 labelCfg.cls += ' col-md-' + this.labelmd;
13612 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13615 if(this.labelsm > 0){
13616 labelCfg.cls += ' col-sm-' + this.labelsm;
13617 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13620 if(this.labelxs > 0){
13621 labelCfg.cls += ' col-xs-' + this.labelxs;
13622 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13626 } else if ( this.fieldLabel.length) {
13627 // Roo.log(" label");
13632 //cls : 'input-group-addon',
13633 html : this.fieldLabel
13638 if(this.indicatorpos == 'right'){
13642 //cls : 'input-group-addon',
13643 html : this.fieldLabel
13653 // Roo.log(" no label && no align");
13660 ['xs','sm','md','lg'].map(function(size){
13661 if (settings[size]) {
13662 cfg.cls += ' col-' + size + '-' + settings[size];
13670 _initEventsCalled : false,
13673 initEvents: function()
13675 if (this._initEventsCalled) { // as we call render... prevent looping...
13678 this._initEventsCalled = true;
13681 throw "can not find store for combo";
13684 this.indicator = this.indicatorEl();
13686 this.store = Roo.factory(this.store, Roo.data);
13687 this.store.parent = this;
13689 // if we are building from html. then this element is so complex, that we can not really
13690 // use the rendered HTML.
13691 // so we have to trash and replace the previous code.
13692 if (Roo.XComponent.build_from_html) {
13693 // remove this element....
13694 var e = this.el.dom, k=0;
13695 while (e ) { e = e.previousSibling; ++k;}
13700 this.rendered = false;
13702 this.render(this.parent().getChildContainer(true), k);
13705 if(Roo.isIOS && this.useNativeIOS){
13706 this.initIOSView();
13714 if(Roo.isTouch && this.mobileTouchView){
13715 this.initTouchView();
13720 this.initTickableEvents();
13724 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13726 if(this.hiddenName){
13728 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13730 this.hiddenField.dom.value =
13731 this.hiddenValue !== undefined ? this.hiddenValue :
13732 this.value !== undefined ? this.value : '';
13734 // prevent input submission
13735 this.el.dom.removeAttribute('name');
13736 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13741 // this.el.dom.setAttribute('autocomplete', 'off');
13744 var cls = 'x-combo-list';
13746 //this.list = new Roo.Layer({
13747 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13753 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13754 _this.list.setWidth(lw);
13757 this.list.on('mouseover', this.onViewOver, this);
13758 this.list.on('mousemove', this.onViewMove, this);
13759 this.list.on('scroll', this.onViewScroll, this);
13762 this.list.swallowEvent('mousewheel');
13763 this.assetHeight = 0;
13766 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13767 this.assetHeight += this.header.getHeight();
13770 this.innerList = this.list.createChild({cls:cls+'-inner'});
13771 this.innerList.on('mouseover', this.onViewOver, this);
13772 this.innerList.on('mousemove', this.onViewMove, this);
13773 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13775 if(this.allowBlank && !this.pageSize && !this.disableClear){
13776 this.footer = this.list.createChild({cls:cls+'-ft'});
13777 this.pageTb = new Roo.Toolbar(this.footer);
13781 this.footer = this.list.createChild({cls:cls+'-ft'});
13782 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13783 {pageSize: this.pageSize});
13787 if (this.pageTb && this.allowBlank && !this.disableClear) {
13789 this.pageTb.add(new Roo.Toolbar.Fill(), {
13790 cls: 'x-btn-icon x-btn-clear',
13792 handler: function()
13795 _this.clearValue();
13796 _this.onSelect(false, -1);
13801 this.assetHeight += this.footer.getHeight();
13806 this.tpl = Roo.bootstrap.version == 4 ?
13807 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13808 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13811 this.view = new Roo.View(this.list, this.tpl, {
13812 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13814 //this.view.wrapEl.setDisplayed(false);
13815 this.view.on('click', this.onViewClick, this);
13818 this.store.on('beforeload', this.onBeforeLoad, this);
13819 this.store.on('load', this.onLoad, this);
13820 this.store.on('loadexception', this.onLoadException, this);
13822 if(this.resizable){
13823 this.resizer = new Roo.Resizable(this.list, {
13824 pinned:true, handles:'se'
13826 this.resizer.on('resize', function(r, w, h){
13827 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13828 this.listWidth = w;
13829 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13830 this.restrictHeight();
13832 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13835 if(!this.editable){
13836 this.editable = true;
13837 this.setEditable(false);
13842 if (typeof(this.events.add.listeners) != 'undefined') {
13844 this.addicon = this.wrap.createChild(
13845 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13847 this.addicon.on('click', function(e) {
13848 this.fireEvent('add', this);
13851 if (typeof(this.events.edit.listeners) != 'undefined') {
13853 this.editicon = this.wrap.createChild(
13854 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13855 if (this.addicon) {
13856 this.editicon.setStyle('margin-left', '40px');
13858 this.editicon.on('click', function(e) {
13860 // we fire even if inothing is selected..
13861 this.fireEvent('edit', this, this.lastData );
13867 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13868 "up" : function(e){
13869 this.inKeyMode = true;
13873 "down" : function(e){
13874 if(!this.isExpanded()){
13875 this.onTriggerClick();
13877 this.inKeyMode = true;
13882 "enter" : function(e){
13883 // this.onViewClick();
13887 if(this.fireEvent("specialkey", this, e)){
13888 this.onViewClick(false);
13894 "esc" : function(e){
13898 "tab" : function(e){
13901 if(this.fireEvent("specialkey", this, e)){
13902 this.onViewClick(false);
13910 doRelay : function(foo, bar, hname){
13911 if(hname == 'down' || this.scope.isExpanded()){
13912 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13921 this.queryDelay = Math.max(this.queryDelay || 10,
13922 this.mode == 'local' ? 10 : 250);
13925 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13927 if(this.typeAhead){
13928 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13930 if(this.editable !== false){
13931 this.inputEl().on("keyup", this.onKeyUp, this);
13933 if(this.forceSelection){
13934 this.inputEl().on('blur', this.doForce, this);
13938 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13939 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13943 initTickableEvents: function()
13947 if(this.hiddenName){
13949 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13951 this.hiddenField.dom.value =
13952 this.hiddenValue !== undefined ? this.hiddenValue :
13953 this.value !== undefined ? this.value : '';
13955 // prevent input submission
13956 this.el.dom.removeAttribute('name');
13957 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13962 // this.list = this.el.select('ul.dropdown-menu',true).first();
13964 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13965 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13966 if(this.triggerList){
13967 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13970 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13971 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13973 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13974 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13976 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13977 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13979 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13980 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13981 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13984 this.cancelBtn.hide();
13989 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13990 _this.list.setWidth(lw);
13993 this.list.on('mouseover', this.onViewOver, this);
13994 this.list.on('mousemove', this.onViewMove, this);
13996 this.list.on('scroll', this.onViewScroll, this);
13999 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14000 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14003 this.view = new Roo.View(this.list, this.tpl, {
14008 selectedClass: this.selectedClass
14011 //this.view.wrapEl.setDisplayed(false);
14012 this.view.on('click', this.onViewClick, this);
14016 this.store.on('beforeload', this.onBeforeLoad, this);
14017 this.store.on('load', this.onLoad, this);
14018 this.store.on('loadexception', this.onLoadException, this);
14021 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14022 "up" : function(e){
14023 this.inKeyMode = true;
14027 "down" : function(e){
14028 this.inKeyMode = true;
14032 "enter" : function(e){
14033 if(this.fireEvent("specialkey", this, e)){
14034 this.onViewClick(false);
14040 "esc" : function(e){
14041 this.onTickableFooterButtonClick(e, false, false);
14044 "tab" : function(e){
14045 this.fireEvent("specialkey", this, e);
14047 this.onTickableFooterButtonClick(e, false, false);
14054 doRelay : function(e, fn, key){
14055 if(this.scope.isExpanded()){
14056 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14065 this.queryDelay = Math.max(this.queryDelay || 10,
14066 this.mode == 'local' ? 10 : 250);
14069 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14071 if(this.typeAhead){
14072 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14075 if(this.editable !== false){
14076 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14079 this.indicator = this.indicatorEl();
14081 if(this.indicator){
14082 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14083 this.indicator.hide();
14088 onDestroy : function(){
14090 this.view.setStore(null);
14091 this.view.el.removeAllListeners();
14092 this.view.el.remove();
14093 this.view.purgeListeners();
14096 this.list.dom.innerHTML = '';
14100 this.store.un('beforeload', this.onBeforeLoad, this);
14101 this.store.un('load', this.onLoad, this);
14102 this.store.un('loadexception', this.onLoadException, this);
14104 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14108 fireKey : function(e){
14109 if(e.isNavKeyPress() && !this.list.isVisible()){
14110 this.fireEvent("specialkey", this, e);
14115 onResize: function(w, h){
14116 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14118 // if(typeof w != 'number'){
14119 // // we do not handle it!?!?
14122 // var tw = this.trigger.getWidth();
14123 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14124 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14126 // this.inputEl().setWidth( this.adjustWidth('input', x));
14128 // //this.trigger.setStyle('left', x+'px');
14130 // if(this.list && this.listWidth === undefined){
14131 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14132 // this.list.setWidth(lw);
14133 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14141 * Allow or prevent the user from directly editing the field text. If false is passed,
14142 * the user will only be able to select from the items defined in the dropdown list. This method
14143 * is the runtime equivalent of setting the 'editable' config option at config time.
14144 * @param {Boolean} value True to allow the user to directly edit the field text
14146 setEditable : function(value){
14147 if(value == this.editable){
14150 this.editable = value;
14152 this.inputEl().dom.setAttribute('readOnly', true);
14153 this.inputEl().on('mousedown', this.onTriggerClick, this);
14154 this.inputEl().addClass('x-combo-noedit');
14156 this.inputEl().dom.setAttribute('readOnly', false);
14157 this.inputEl().un('mousedown', this.onTriggerClick, this);
14158 this.inputEl().removeClass('x-combo-noedit');
14164 onBeforeLoad : function(combo,opts){
14165 if(!this.hasFocus){
14169 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14171 this.restrictHeight();
14172 this.selectedIndex = -1;
14176 onLoad : function(){
14178 this.hasQuery = false;
14180 if(!this.hasFocus){
14184 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14185 this.loading.hide();
14188 if(this.store.getCount() > 0){
14191 this.restrictHeight();
14192 if(this.lastQuery == this.allQuery){
14193 if(this.editable && !this.tickable){
14194 this.inputEl().dom.select();
14198 !this.selectByValue(this.value, true) &&
14201 !this.store.lastOptions ||
14202 typeof(this.store.lastOptions.add) == 'undefined' ||
14203 this.store.lastOptions.add != true
14206 this.select(0, true);
14209 if(this.autoFocus){
14212 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14213 this.taTask.delay(this.typeAheadDelay);
14217 this.onEmptyResults();
14223 onLoadException : function()
14225 this.hasQuery = false;
14227 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14228 this.loading.hide();
14231 if(this.tickable && this.editable){
14236 // only causes errors at present
14237 //Roo.log(this.store.reader.jsonData);
14238 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14240 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14246 onTypeAhead : function(){
14247 if(this.store.getCount() > 0){
14248 var r = this.store.getAt(0);
14249 var newValue = r.data[this.displayField];
14250 var len = newValue.length;
14251 var selStart = this.getRawValue().length;
14253 if(selStart != len){
14254 this.setRawValue(newValue);
14255 this.selectText(selStart, newValue.length);
14261 onSelect : function(record, index){
14263 if(this.fireEvent('beforeselect', this, record, index) !== false){
14265 this.setFromData(index > -1 ? record.data : false);
14268 this.fireEvent('select', this, record, index);
14273 * Returns the currently selected field value or empty string if no value is set.
14274 * @return {String} value The selected value
14276 getValue : function()
14278 if(Roo.isIOS && this.useNativeIOS){
14279 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14283 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14286 if(this.valueField){
14287 return typeof this.value != 'undefined' ? this.value : '';
14289 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14293 getRawValue : function()
14295 if(Roo.isIOS && this.useNativeIOS){
14296 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14299 var v = this.inputEl().getValue();
14305 * Clears any text/value currently set in the field
14307 clearValue : function(){
14309 if(this.hiddenField){
14310 this.hiddenField.dom.value = '';
14313 this.setRawValue('');
14314 this.lastSelectionText = '';
14315 this.lastData = false;
14317 var close = this.closeTriggerEl();
14328 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14329 * will be displayed in the field. If the value does not match the data value of an existing item,
14330 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14331 * Otherwise the field will be blank (although the value will still be set).
14332 * @param {String} value The value to match
14334 setValue : function(v)
14336 if(Roo.isIOS && this.useNativeIOS){
14337 this.setIOSValue(v);
14347 if(this.valueField){
14348 var r = this.findRecord(this.valueField, v);
14350 text = r.data[this.displayField];
14351 }else if(this.valueNotFoundText !== undefined){
14352 text = this.valueNotFoundText;
14355 this.lastSelectionText = text;
14356 if(this.hiddenField){
14357 this.hiddenField.dom.value = v;
14359 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14362 var close = this.closeTriggerEl();
14365 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14371 * @property {Object} the last set data for the element
14376 * Sets the value of the field based on a object which is related to the record format for the store.
14377 * @param {Object} value the value to set as. or false on reset?
14379 setFromData : function(o){
14386 var dv = ''; // display value
14387 var vv = ''; // value value..
14389 if (this.displayField) {
14390 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14392 // this is an error condition!!!
14393 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14396 if(this.valueField){
14397 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14400 var close = this.closeTriggerEl();
14403 if(dv.length || vv * 1 > 0){
14405 this.blockFocus=true;
14411 if(this.hiddenField){
14412 this.hiddenField.dom.value = vv;
14414 this.lastSelectionText = dv;
14415 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14419 // no hidden field.. - we store the value in 'value', but still display
14420 // display field!!!!
14421 this.lastSelectionText = dv;
14422 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14429 reset : function(){
14430 // overridden so that last data is reset..
14437 this.setValue(this.originalValue);
14438 //this.clearInvalid();
14439 this.lastData = false;
14441 this.view.clearSelections();
14447 findRecord : function(prop, value){
14449 if(this.store.getCount() > 0){
14450 this.store.each(function(r){
14451 if(r.data[prop] == value){
14461 getName: function()
14463 // returns hidden if it's set..
14464 if (!this.rendered) {return ''};
14465 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14469 onViewMove : function(e, t){
14470 this.inKeyMode = false;
14474 onViewOver : function(e, t){
14475 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14478 var item = this.view.findItemFromChild(t);
14481 var index = this.view.indexOf(item);
14482 this.select(index, false);
14487 onViewClick : function(view, doFocus, el, e)
14489 var index = this.view.getSelectedIndexes()[0];
14491 var r = this.store.getAt(index);
14495 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14502 Roo.each(this.tickItems, function(v,k){
14504 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14506 _this.tickItems.splice(k, 1);
14508 if(typeof(e) == 'undefined' && view == false){
14509 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14521 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14522 this.tickItems.push(r.data);
14525 if(typeof(e) == 'undefined' && view == false){
14526 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14533 this.onSelect(r, index);
14535 if(doFocus !== false && !this.blockFocus){
14536 this.inputEl().focus();
14541 restrictHeight : function(){
14542 //this.innerList.dom.style.height = '';
14543 //var inner = this.innerList.dom;
14544 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14545 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14546 //this.list.beginUpdate();
14547 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14548 this.list.alignTo(this.inputEl(), this.listAlign);
14549 this.list.alignTo(this.inputEl(), this.listAlign);
14550 //this.list.endUpdate();
14554 onEmptyResults : function(){
14556 if(this.tickable && this.editable){
14557 this.hasFocus = false;
14558 this.restrictHeight();
14566 * Returns true if the dropdown list is expanded, else false.
14568 isExpanded : function(){
14569 return this.list.isVisible();
14573 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14574 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14575 * @param {String} value The data value of the item to select
14576 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14577 * selected item if it is not currently in view (defaults to true)
14578 * @return {Boolean} True if the value matched an item in the list, else false
14580 selectByValue : function(v, scrollIntoView){
14581 if(v !== undefined && v !== null){
14582 var r = this.findRecord(this.valueField || this.displayField, v);
14584 this.select(this.store.indexOf(r), scrollIntoView);
14592 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14593 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14594 * @param {Number} index The zero-based index of the list item to select
14595 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14596 * selected item if it is not currently in view (defaults to true)
14598 select : function(index, scrollIntoView){
14599 this.selectedIndex = index;
14600 this.view.select(index);
14601 if(scrollIntoView !== false){
14602 var el = this.view.getNode(index);
14604 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14607 this.list.scrollChildIntoView(el, false);
14613 selectNext : function(){
14614 var ct = this.store.getCount();
14616 if(this.selectedIndex == -1){
14618 }else if(this.selectedIndex < ct-1){
14619 this.select(this.selectedIndex+1);
14625 selectPrev : function(){
14626 var ct = this.store.getCount();
14628 if(this.selectedIndex == -1){
14630 }else if(this.selectedIndex != 0){
14631 this.select(this.selectedIndex-1);
14637 onKeyUp : function(e){
14638 if(this.editable !== false && !e.isSpecialKey()){
14639 this.lastKey = e.getKey();
14640 this.dqTask.delay(this.queryDelay);
14645 validateBlur : function(){
14646 return !this.list || !this.list.isVisible();
14650 initQuery : function(){
14652 var v = this.getRawValue();
14654 if(this.tickable && this.editable){
14655 v = this.tickableInputEl().getValue();
14662 doForce : function(){
14663 if(this.inputEl().dom.value.length > 0){
14664 this.inputEl().dom.value =
14665 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14671 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14672 * query allowing the query action to be canceled if needed.
14673 * @param {String} query The SQL query to execute
14674 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14675 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14676 * saved in the current store (defaults to false)
14678 doQuery : function(q, forceAll){
14680 if(q === undefined || q === null){
14685 forceAll: forceAll,
14689 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14694 forceAll = qe.forceAll;
14695 if(forceAll === true || (q.length >= this.minChars)){
14697 this.hasQuery = true;
14699 if(this.lastQuery != q || this.alwaysQuery){
14700 this.lastQuery = q;
14701 if(this.mode == 'local'){
14702 this.selectedIndex = -1;
14704 this.store.clearFilter();
14707 if(this.specialFilter){
14708 this.fireEvent('specialfilter', this);
14713 this.store.filter(this.displayField, q);
14716 this.store.fireEvent("datachanged", this.store);
14723 this.store.baseParams[this.queryParam] = q;
14725 var options = {params : this.getParams(q)};
14728 options.add = true;
14729 options.params.start = this.page * this.pageSize;
14732 this.store.load(options);
14735 * this code will make the page width larger, at the beginning, the list not align correctly,
14736 * we should expand the list on onLoad
14737 * so command out it
14742 this.selectedIndex = -1;
14747 this.loadNext = false;
14751 getParams : function(q){
14753 //p[this.queryParam] = q;
14757 p.limit = this.pageSize;
14763 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14765 collapse : function(){
14766 if(!this.isExpanded()){
14772 this.hasFocus = false;
14776 this.cancelBtn.hide();
14777 this.trigger.show();
14780 this.tickableInputEl().dom.value = '';
14781 this.tickableInputEl().blur();
14786 Roo.get(document).un('mousedown', this.collapseIf, this);
14787 Roo.get(document).un('mousewheel', this.collapseIf, this);
14788 if (!this.editable) {
14789 Roo.get(document).un('keydown', this.listKeyPress, this);
14791 this.fireEvent('collapse', this);
14797 collapseIf : function(e){
14798 var in_combo = e.within(this.el);
14799 var in_list = e.within(this.list);
14800 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14802 if (in_combo || in_list || is_list) {
14803 //e.stopPropagation();
14808 this.onTickableFooterButtonClick(e, false, false);
14816 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14818 expand : function(){
14820 if(this.isExpanded() || !this.hasFocus){
14824 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14825 this.list.setWidth(lw);
14831 this.restrictHeight();
14835 this.tickItems = Roo.apply([], this.item);
14838 this.cancelBtn.show();
14839 this.trigger.hide();
14842 this.tickableInputEl().focus();
14847 Roo.get(document).on('mousedown', this.collapseIf, this);
14848 Roo.get(document).on('mousewheel', this.collapseIf, this);
14849 if (!this.editable) {
14850 Roo.get(document).on('keydown', this.listKeyPress, this);
14853 this.fireEvent('expand', this);
14857 // Implements the default empty TriggerField.onTriggerClick function
14858 onTriggerClick : function(e)
14860 Roo.log('trigger click');
14862 if(this.disabled || !this.triggerList){
14867 this.loadNext = false;
14869 if(this.isExpanded()){
14871 if (!this.blockFocus) {
14872 this.inputEl().focus();
14876 this.hasFocus = true;
14877 if(this.triggerAction == 'all') {
14878 this.doQuery(this.allQuery, true);
14880 this.doQuery(this.getRawValue());
14882 if (!this.blockFocus) {
14883 this.inputEl().focus();
14888 onTickableTriggerClick : function(e)
14895 this.loadNext = false;
14896 this.hasFocus = true;
14898 if(this.triggerAction == 'all') {
14899 this.doQuery(this.allQuery, true);
14901 this.doQuery(this.getRawValue());
14905 onSearchFieldClick : function(e)
14907 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14908 this.onTickableFooterButtonClick(e, false, false);
14912 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14917 this.loadNext = false;
14918 this.hasFocus = true;
14920 if(this.triggerAction == 'all') {
14921 this.doQuery(this.allQuery, true);
14923 this.doQuery(this.getRawValue());
14927 listKeyPress : function(e)
14929 //Roo.log('listkeypress');
14930 // scroll to first matching element based on key pres..
14931 if (e.isSpecialKey()) {
14934 var k = String.fromCharCode(e.getKey()).toUpperCase();
14937 var csel = this.view.getSelectedNodes();
14938 var cselitem = false;
14940 var ix = this.view.indexOf(csel[0]);
14941 cselitem = this.store.getAt(ix);
14942 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14948 this.store.each(function(v) {
14950 // start at existing selection.
14951 if (cselitem.id == v.id) {
14957 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14958 match = this.store.indexOf(v);
14964 if (match === false) {
14965 return true; // no more action?
14968 this.view.select(match);
14969 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14970 sn.scrollIntoView(sn.dom.parentNode, false);
14973 onViewScroll : function(e, t){
14975 if(this.view.el.getScroll().top == 0 ||this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
14979 this.hasQuery = true;
14981 this.loading = this.list.select('.loading', true).first();
14983 if(this.loading === null){
14984 this.list.createChild({
14986 cls: 'loading roo-select2-more-results roo-select2-active',
14987 html: 'Loading more results...'
14990 this.loading = this.list.select('.loading', true).first();
14992 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14994 this.loading.hide();
14997 this.loading.show();
15002 this.loadNext = true;
15004 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15009 addItem : function(o)
15011 var dv = ''; // display value
15013 if (this.displayField) {
15014 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15016 // this is an error condition!!!
15017 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15024 var choice = this.choices.createChild({
15026 cls: 'roo-select2-search-choice',
15035 cls: 'roo-select2-search-choice-close fa fa-times',
15040 }, this.searchField);
15042 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15044 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15052 this.inputEl().dom.value = '';
15057 onRemoveItem : function(e, _self, o)
15059 e.preventDefault();
15061 this.lastItem = Roo.apply([], this.item);
15063 var index = this.item.indexOf(o.data) * 1;
15066 Roo.log('not this item?!');
15070 this.item.splice(index, 1);
15075 this.fireEvent('remove', this, e);
15081 syncValue : function()
15083 if(!this.item.length){
15090 Roo.each(this.item, function(i){
15091 if(_this.valueField){
15092 value.push(i[_this.valueField]);
15099 this.value = value.join(',');
15101 if(this.hiddenField){
15102 this.hiddenField.dom.value = this.value;
15105 this.store.fireEvent("datachanged", this.store);
15110 clearItem : function()
15112 if(!this.multiple){
15118 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15126 if(this.tickable && !Roo.isTouch){
15127 this.view.refresh();
15131 inputEl: function ()
15133 if(Roo.isIOS && this.useNativeIOS){
15134 return this.el.select('select.roo-ios-select', true).first();
15137 if(Roo.isTouch && this.mobileTouchView){
15138 return this.el.select('input.form-control',true).first();
15142 return this.searchField;
15145 return this.el.select('input.form-control',true).first();
15148 onTickableFooterButtonClick : function(e, btn, el)
15150 e.preventDefault();
15152 this.lastItem = Roo.apply([], this.item);
15154 if(btn && btn.name == 'cancel'){
15155 this.tickItems = Roo.apply([], this.item);
15164 Roo.each(this.tickItems, function(o){
15172 validate : function()
15174 if(this.getVisibilityEl().hasClass('hidden')){
15178 var v = this.getRawValue();
15181 v = this.getValue();
15184 if(this.disabled || this.allowBlank || v.length){
15189 this.markInvalid();
15193 tickableInputEl : function()
15195 if(!this.tickable || !this.editable){
15196 return this.inputEl();
15199 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15203 getAutoCreateTouchView : function()
15208 cls: 'form-group' //input-group
15214 type : this.inputType,
15215 cls : 'form-control x-combo-noedit',
15216 autocomplete: 'new-password',
15217 placeholder : this.placeholder || '',
15222 input.name = this.name;
15226 input.cls += ' input-' + this.size;
15229 if (this.disabled) {
15230 input.disabled = true;
15241 inputblock.cls += ' input-group';
15243 inputblock.cn.unshift({
15245 cls : 'input-group-addon input-group-prepend input-group-text',
15250 if(this.removable && !this.multiple){
15251 inputblock.cls += ' roo-removable';
15253 inputblock.cn.push({
15256 cls : 'roo-combo-removable-btn close'
15260 if(this.hasFeedback && !this.allowBlank){
15262 inputblock.cls += ' has-feedback';
15264 inputblock.cn.push({
15266 cls: 'glyphicon form-control-feedback'
15273 inputblock.cls += (this.before) ? '' : ' input-group';
15275 inputblock.cn.push({
15277 cls : 'input-group-addon input-group-append input-group-text',
15283 var ibwrap = inputblock;
15288 cls: 'roo-select2-choices',
15292 cls: 'roo-select2-search-field',
15305 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15310 cls: 'form-hidden-field'
15316 if(!this.multiple && this.showToggleBtn){
15323 if (this.caret != false) {
15326 cls: 'fa fa-' + this.caret
15333 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15338 cls: 'combobox-clear',
15352 combobox.cls += ' roo-select2-container-multi';
15355 var align = this.labelAlign || this.parentLabelAlign();
15357 if (align ==='left' && this.fieldLabel.length) {
15362 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15363 tooltip : 'This field is required'
15367 cls : 'control-label col-form-label',
15368 html : this.fieldLabel
15379 var labelCfg = cfg.cn[1];
15380 var contentCfg = cfg.cn[2];
15383 if(this.indicatorpos == 'right'){
15388 cls : 'control-label col-form-label',
15392 html : this.fieldLabel
15396 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15397 tooltip : 'This field is required'
15410 labelCfg = cfg.cn[0];
15411 contentCfg = cfg.cn[1];
15416 if(this.labelWidth > 12){
15417 labelCfg.style = "width: " + this.labelWidth + 'px';
15420 if(this.labelWidth < 13 && this.labelmd == 0){
15421 this.labelmd = this.labelWidth;
15424 if(this.labellg > 0){
15425 labelCfg.cls += ' col-lg-' + this.labellg;
15426 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15429 if(this.labelmd > 0){
15430 labelCfg.cls += ' col-md-' + this.labelmd;
15431 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15434 if(this.labelsm > 0){
15435 labelCfg.cls += ' col-sm-' + this.labelsm;
15436 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15439 if(this.labelxs > 0){
15440 labelCfg.cls += ' col-xs-' + this.labelxs;
15441 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15445 } else if ( this.fieldLabel.length) {
15449 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15450 tooltip : 'This field is required'
15454 cls : 'control-label',
15455 html : this.fieldLabel
15466 if(this.indicatorpos == 'right'){
15470 cls : 'control-label',
15471 html : this.fieldLabel,
15475 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15476 tooltip : 'This field is required'
15493 var settings = this;
15495 ['xs','sm','md','lg'].map(function(size){
15496 if (settings[size]) {
15497 cfg.cls += ' col-' + size + '-' + settings[size];
15504 initTouchView : function()
15506 this.renderTouchView();
15508 this.touchViewEl.on('scroll', function(){
15509 this.el.dom.scrollTop = 0;
15512 this.originalValue = this.getValue();
15514 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15516 this.inputEl().on("click", this.showTouchView, this);
15517 if (this.triggerEl) {
15518 this.triggerEl.on("click", this.showTouchView, this);
15522 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15523 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15525 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15527 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15528 this.store.on('load', this.onTouchViewLoad, this);
15529 this.store.on('loadexception', this.onTouchViewLoadException, this);
15531 if(this.hiddenName){
15533 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15535 this.hiddenField.dom.value =
15536 this.hiddenValue !== undefined ? this.hiddenValue :
15537 this.value !== undefined ? this.value : '';
15539 this.el.dom.removeAttribute('name');
15540 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15544 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15545 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15548 if(this.removable && !this.multiple){
15549 var close = this.closeTriggerEl();
15551 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15552 close.on('click', this.removeBtnClick, this, close);
15556 * fix the bug in Safari iOS8
15558 this.inputEl().on("focus", function(e){
15559 document.activeElement.blur();
15562 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15569 renderTouchView : function()
15571 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15572 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15574 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15575 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15577 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15578 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15579 this.touchViewBodyEl.setStyle('overflow', 'auto');
15581 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15582 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15584 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15585 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15589 showTouchView : function()
15595 this.touchViewHeaderEl.hide();
15597 if(this.modalTitle.length){
15598 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15599 this.touchViewHeaderEl.show();
15602 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15603 this.touchViewEl.show();
15605 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15607 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15608 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15610 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15612 if(this.modalTitle.length){
15613 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15616 this.touchViewBodyEl.setHeight(bodyHeight);
15620 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15622 this.touchViewEl.addClass('in');
15625 if(this._touchViewMask){
15626 Roo.get(document.body).addClass("x-body-masked");
15627 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15628 this._touchViewMask.setStyle('z-index', 10000);
15629 this._touchViewMask.addClass('show');
15632 this.doTouchViewQuery();
15636 hideTouchView : function()
15638 this.touchViewEl.removeClass('in');
15642 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15644 this.touchViewEl.setStyle('display', 'none');
15647 if(this._touchViewMask){
15648 this._touchViewMask.removeClass('show');
15649 Roo.get(document.body).removeClass("x-body-masked");
15653 setTouchViewValue : function()
15660 Roo.each(this.tickItems, function(o){
15665 this.hideTouchView();
15668 doTouchViewQuery : function()
15677 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15681 if(!this.alwaysQuery || this.mode == 'local'){
15682 this.onTouchViewLoad();
15689 onTouchViewBeforeLoad : function(combo,opts)
15695 onTouchViewLoad : function()
15697 if(this.store.getCount() < 1){
15698 this.onTouchViewEmptyResults();
15702 this.clearTouchView();
15704 var rawValue = this.getRawValue();
15706 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15708 this.tickItems = [];
15710 this.store.data.each(function(d, rowIndex){
15711 var row = this.touchViewListGroup.createChild(template);
15713 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15714 row.addClass(d.data.cls);
15717 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15720 html : d.data[this.displayField]
15723 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15724 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15727 row.removeClass('selected');
15728 if(!this.multiple && this.valueField &&
15729 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15732 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15733 row.addClass('selected');
15736 if(this.multiple && this.valueField &&
15737 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15741 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15742 this.tickItems.push(d.data);
15745 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15749 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15751 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15753 if(this.modalTitle.length){
15754 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15757 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15759 if(this.mobile_restrict_height && listHeight < bodyHeight){
15760 this.touchViewBodyEl.setHeight(listHeight);
15765 if(firstChecked && listHeight > bodyHeight){
15766 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15771 onTouchViewLoadException : function()
15773 this.hideTouchView();
15776 onTouchViewEmptyResults : function()
15778 this.clearTouchView();
15780 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15782 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15786 clearTouchView : function()
15788 this.touchViewListGroup.dom.innerHTML = '';
15791 onTouchViewClick : function(e, el, o)
15793 e.preventDefault();
15796 var rowIndex = o.rowIndex;
15798 var r = this.store.getAt(rowIndex);
15800 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15802 if(!this.multiple){
15803 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15804 c.dom.removeAttribute('checked');
15807 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15809 this.setFromData(r.data);
15811 var close = this.closeTriggerEl();
15817 this.hideTouchView();
15819 this.fireEvent('select', this, r, rowIndex);
15824 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15825 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15826 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15830 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15831 this.addItem(r.data);
15832 this.tickItems.push(r.data);
15836 getAutoCreateNativeIOS : function()
15839 cls: 'form-group' //input-group,
15844 cls : 'roo-ios-select'
15848 combobox.name = this.name;
15851 if (this.disabled) {
15852 combobox.disabled = true;
15855 var settings = this;
15857 ['xs','sm','md','lg'].map(function(size){
15858 if (settings[size]) {
15859 cfg.cls += ' col-' + size + '-' + settings[size];
15869 initIOSView : function()
15871 this.store.on('load', this.onIOSViewLoad, this);
15876 onIOSViewLoad : function()
15878 if(this.store.getCount() < 1){
15882 this.clearIOSView();
15884 if(this.allowBlank) {
15886 var default_text = '-- SELECT --';
15888 if(this.placeholder.length){
15889 default_text = this.placeholder;
15892 if(this.emptyTitle.length){
15893 default_text += ' - ' + this.emptyTitle + ' -';
15896 var opt = this.inputEl().createChild({
15899 html : default_text
15903 o[this.valueField] = 0;
15904 o[this.displayField] = default_text;
15906 this.ios_options.push({
15913 this.store.data.each(function(d, rowIndex){
15917 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15918 html = d.data[this.displayField];
15923 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15924 value = d.data[this.valueField];
15933 if(this.value == d.data[this.valueField]){
15934 option['selected'] = true;
15937 var opt = this.inputEl().createChild(option);
15939 this.ios_options.push({
15946 this.inputEl().on('change', function(){
15947 this.fireEvent('select', this);
15952 clearIOSView: function()
15954 this.inputEl().dom.innerHTML = '';
15956 this.ios_options = [];
15959 setIOSValue: function(v)
15963 if(!this.ios_options){
15967 Roo.each(this.ios_options, function(opts){
15969 opts.el.dom.removeAttribute('selected');
15971 if(opts.data[this.valueField] != v){
15975 opts.el.dom.setAttribute('selected', true);
15981 * @cfg {Boolean} grow
15985 * @cfg {Number} growMin
15989 * @cfg {Number} growMax
15998 Roo.apply(Roo.bootstrap.ComboBox, {
16002 cls: 'modal-header',
16024 cls: 'list-group-item',
16028 cls: 'roo-combobox-list-group-item-value'
16032 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16046 listItemCheckbox : {
16048 cls: 'list-group-item',
16052 cls: 'roo-combobox-list-group-item-value'
16056 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16072 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16077 cls: 'modal-footer',
16085 cls: 'col-xs-6 text-left',
16088 cls: 'btn btn-danger roo-touch-view-cancel',
16094 cls: 'col-xs-6 text-right',
16097 cls: 'btn btn-success roo-touch-view-ok',
16108 Roo.apply(Roo.bootstrap.ComboBox, {
16110 touchViewTemplate : {
16112 cls: 'modal fade roo-combobox-touch-view',
16116 cls: 'modal-dialog',
16117 style : 'position:fixed', // we have to fix position....
16121 cls: 'modal-content',
16123 Roo.bootstrap.ComboBox.header,
16124 Roo.bootstrap.ComboBox.body,
16125 Roo.bootstrap.ComboBox.footer
16134 * Ext JS Library 1.1.1
16135 * Copyright(c) 2006-2007, Ext JS, LLC.
16137 * Originally Released Under LGPL - original licence link has changed is not relivant.
16140 * <script type="text/javascript">
16145 * @extends Roo.util.Observable
16146 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16147 * This class also supports single and multi selection modes. <br>
16148 * Create a data model bound view:
16150 var store = new Roo.data.Store(...);
16152 var view = new Roo.View({
16154 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16156 singleSelect: true,
16157 selectedClass: "ydataview-selected",
16161 // listen for node click?
16162 view.on("click", function(vw, index, node, e){
16163 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16167 dataModel.load("foobar.xml");
16169 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16171 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16172 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16174 * Note: old style constructor is still suported (container, template, config)
16177 * Create a new View
16178 * @param {Object} config The config object
16181 Roo.View = function(config, depreciated_tpl, depreciated_config){
16183 this.parent = false;
16185 if (typeof(depreciated_tpl) == 'undefined') {
16186 // new way.. - universal constructor.
16187 Roo.apply(this, config);
16188 this.el = Roo.get(this.el);
16191 this.el = Roo.get(config);
16192 this.tpl = depreciated_tpl;
16193 Roo.apply(this, depreciated_config);
16195 this.wrapEl = this.el.wrap().wrap();
16196 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16199 if(typeof(this.tpl) == "string"){
16200 this.tpl = new Roo.Template(this.tpl);
16202 // support xtype ctors..
16203 this.tpl = new Roo.factory(this.tpl, Roo);
16207 this.tpl.compile();
16212 * @event beforeclick
16213 * Fires before a click is processed. Returns false to cancel the default action.
16214 * @param {Roo.View} this
16215 * @param {Number} index The index of the target node
16216 * @param {HTMLElement} node The target node
16217 * @param {Roo.EventObject} e The raw event object
16219 "beforeclick" : true,
16222 * Fires when a template node is clicked.
16223 * @param {Roo.View} this
16224 * @param {Number} index The index of the target node
16225 * @param {HTMLElement} node The target node
16226 * @param {Roo.EventObject} e The raw event object
16231 * Fires when a template node is double clicked.
16232 * @param {Roo.View} this
16233 * @param {Number} index The index of the target node
16234 * @param {HTMLElement} node The target node
16235 * @param {Roo.EventObject} e The raw event object
16239 * @event contextmenu
16240 * Fires when a template node is right clicked.
16241 * @param {Roo.View} this
16242 * @param {Number} index The index of the target node
16243 * @param {HTMLElement} node The target node
16244 * @param {Roo.EventObject} e The raw event object
16246 "contextmenu" : true,
16248 * @event selectionchange
16249 * Fires when the selected nodes change.
16250 * @param {Roo.View} this
16251 * @param {Array} selections Array of the selected nodes
16253 "selectionchange" : true,
16256 * @event beforeselect
16257 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16258 * @param {Roo.View} this
16259 * @param {HTMLElement} node The node to be selected
16260 * @param {Array} selections Array of currently selected nodes
16262 "beforeselect" : true,
16264 * @event preparedata
16265 * Fires on every row to render, to allow you to change the data.
16266 * @param {Roo.View} this
16267 * @param {Object} data to be rendered (change this)
16269 "preparedata" : true
16277 "click": this.onClick,
16278 "dblclick": this.onDblClick,
16279 "contextmenu": this.onContextMenu,
16283 this.selections = [];
16285 this.cmp = new Roo.CompositeElementLite([]);
16287 this.store = Roo.factory(this.store, Roo.data);
16288 this.setStore(this.store, true);
16291 if ( this.footer && this.footer.xtype) {
16293 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16295 this.footer.dataSource = this.store;
16296 this.footer.container = fctr;
16297 this.footer = Roo.factory(this.footer, Roo);
16298 fctr.insertFirst(this.el);
16300 // this is a bit insane - as the paging toolbar seems to detach the el..
16301 // dom.parentNode.parentNode.parentNode
16302 // they get detached?
16306 Roo.View.superclass.constructor.call(this);
16311 Roo.extend(Roo.View, Roo.util.Observable, {
16314 * @cfg {Roo.data.Store} store Data store to load data from.
16319 * @cfg {String|Roo.Element} el The container element.
16324 * @cfg {String|Roo.Template} tpl The template used by this View
16328 * @cfg {String} dataName the named area of the template to use as the data area
16329 * Works with domtemplates roo-name="name"
16333 * @cfg {String} selectedClass The css class to add to selected nodes
16335 selectedClass : "x-view-selected",
16337 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16342 * @cfg {String} text to display on mask (default Loading)
16346 * @cfg {Boolean} multiSelect Allow multiple selection
16348 multiSelect : false,
16350 * @cfg {Boolean} singleSelect Allow single selection
16352 singleSelect: false,
16355 * @cfg {Boolean} toggleSelect - selecting
16357 toggleSelect : false,
16360 * @cfg {Boolean} tickable - selecting
16365 * Returns the element this view is bound to.
16366 * @return {Roo.Element}
16368 getEl : function(){
16369 return this.wrapEl;
16375 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16377 refresh : function(){
16378 //Roo.log('refresh');
16381 // if we are using something like 'domtemplate', then
16382 // the what gets used is:
16383 // t.applySubtemplate(NAME, data, wrapping data..)
16384 // the outer template then get' applied with
16385 // the store 'extra data'
16386 // and the body get's added to the
16387 // roo-name="data" node?
16388 // <span class='roo-tpl-{name}'></span> ?????
16392 this.clearSelections();
16393 this.el.update("");
16395 var records = this.store.getRange();
16396 if(records.length < 1) {
16398 // is this valid?? = should it render a template??
16400 this.el.update(this.emptyText);
16404 if (this.dataName) {
16405 this.el.update(t.apply(this.store.meta)); //????
16406 el = this.el.child('.roo-tpl-' + this.dataName);
16409 for(var i = 0, len = records.length; i < len; i++){
16410 var data = this.prepareData(records[i].data, i, records[i]);
16411 this.fireEvent("preparedata", this, data, i, records[i]);
16413 var d = Roo.apply({}, data);
16416 Roo.apply(d, {'roo-id' : Roo.id()});
16420 Roo.each(this.parent.item, function(item){
16421 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16424 Roo.apply(d, {'roo-data-checked' : 'checked'});
16428 html[html.length] = Roo.util.Format.trim(
16430 t.applySubtemplate(this.dataName, d, this.store.meta) :
16437 el.update(html.join(""));
16438 this.nodes = el.dom.childNodes;
16439 this.updateIndexes(0);
16444 * Function to override to reformat the data that is sent to
16445 * the template for each node.
16446 * DEPRICATED - use the preparedata event handler.
16447 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16448 * a JSON object for an UpdateManager bound view).
16450 prepareData : function(data, index, record)
16452 this.fireEvent("preparedata", this, data, index, record);
16456 onUpdate : function(ds, record){
16457 // Roo.log('on update');
16458 this.clearSelections();
16459 var index = this.store.indexOf(record);
16460 var n = this.nodes[index];
16461 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16462 n.parentNode.removeChild(n);
16463 this.updateIndexes(index, index);
16469 onAdd : function(ds, records, index)
16471 //Roo.log(['on Add', ds, records, index] );
16472 this.clearSelections();
16473 if(this.nodes.length == 0){
16477 var n = this.nodes[index];
16478 for(var i = 0, len = records.length; i < len; i++){
16479 var d = this.prepareData(records[i].data, i, records[i]);
16481 this.tpl.insertBefore(n, d);
16484 this.tpl.append(this.el, d);
16487 this.updateIndexes(index);
16490 onRemove : function(ds, record, index){
16491 // Roo.log('onRemove');
16492 this.clearSelections();
16493 var el = this.dataName ?
16494 this.el.child('.roo-tpl-' + this.dataName) :
16497 el.dom.removeChild(this.nodes[index]);
16498 this.updateIndexes(index);
16502 * Refresh an individual node.
16503 * @param {Number} index
16505 refreshNode : function(index){
16506 this.onUpdate(this.store, this.store.getAt(index));
16509 updateIndexes : function(startIndex, endIndex){
16510 var ns = this.nodes;
16511 startIndex = startIndex || 0;
16512 endIndex = endIndex || ns.length - 1;
16513 for(var i = startIndex; i <= endIndex; i++){
16514 ns[i].nodeIndex = i;
16519 * Changes the data store this view uses and refresh the view.
16520 * @param {Store} store
16522 setStore : function(store, initial){
16523 if(!initial && this.store){
16524 this.store.un("datachanged", this.refresh);
16525 this.store.un("add", this.onAdd);
16526 this.store.un("remove", this.onRemove);
16527 this.store.un("update", this.onUpdate);
16528 this.store.un("clear", this.refresh);
16529 this.store.un("beforeload", this.onBeforeLoad);
16530 this.store.un("load", this.onLoad);
16531 this.store.un("loadexception", this.onLoad);
16535 store.on("datachanged", this.refresh, this);
16536 store.on("add", this.onAdd, this);
16537 store.on("remove", this.onRemove, this);
16538 store.on("update", this.onUpdate, this);
16539 store.on("clear", this.refresh, this);
16540 store.on("beforeload", this.onBeforeLoad, this);
16541 store.on("load", this.onLoad, this);
16542 store.on("loadexception", this.onLoad, this);
16550 * onbeforeLoad - masks the loading area.
16553 onBeforeLoad : function(store,opts)
16555 //Roo.log('onBeforeLoad');
16557 this.el.update("");
16559 this.el.mask(this.mask ? this.mask : "Loading" );
16561 onLoad : function ()
16568 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16569 * @param {HTMLElement} node
16570 * @return {HTMLElement} The template node
16572 findItemFromChild : function(node){
16573 var el = this.dataName ?
16574 this.el.child('.roo-tpl-' + this.dataName,true) :
16577 if(!node || node.parentNode == el){
16580 var p = node.parentNode;
16581 while(p && p != el){
16582 if(p.parentNode == el){
16591 onClick : function(e){
16592 var item = this.findItemFromChild(e.getTarget());
16594 var index = this.indexOf(item);
16595 if(this.onItemClick(item, index, e) !== false){
16596 this.fireEvent("click", this, index, item, e);
16599 this.clearSelections();
16604 onContextMenu : function(e){
16605 var item = this.findItemFromChild(e.getTarget());
16607 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16612 onDblClick : function(e){
16613 var item = this.findItemFromChild(e.getTarget());
16615 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16619 onItemClick : function(item, index, e)
16621 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16624 if (this.toggleSelect) {
16625 var m = this.isSelected(item) ? 'unselect' : 'select';
16628 _t[m](item, true, false);
16631 if(this.multiSelect || this.singleSelect){
16632 if(this.multiSelect && e.shiftKey && this.lastSelection){
16633 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16635 this.select(item, this.multiSelect && e.ctrlKey);
16636 this.lastSelection = item;
16639 if(!this.tickable){
16640 e.preventDefault();
16648 * Get the number of selected nodes.
16651 getSelectionCount : function(){
16652 return this.selections.length;
16656 * Get the currently selected nodes.
16657 * @return {Array} An array of HTMLElements
16659 getSelectedNodes : function(){
16660 return this.selections;
16664 * Get the indexes of the selected nodes.
16667 getSelectedIndexes : function(){
16668 var indexes = [], s = this.selections;
16669 for(var i = 0, len = s.length; i < len; i++){
16670 indexes.push(s[i].nodeIndex);
16676 * Clear all selections
16677 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16679 clearSelections : function(suppressEvent){
16680 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16681 this.cmp.elements = this.selections;
16682 this.cmp.removeClass(this.selectedClass);
16683 this.selections = [];
16684 if(!suppressEvent){
16685 this.fireEvent("selectionchange", this, this.selections);
16691 * Returns true if the passed node is selected
16692 * @param {HTMLElement/Number} node The node or node index
16693 * @return {Boolean}
16695 isSelected : function(node){
16696 var s = this.selections;
16700 node = this.getNode(node);
16701 return s.indexOf(node) !== -1;
16706 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
16707 * @param {Boolean} keepExisting (optional) true to keep existing selections
16708 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16710 select : function(nodeInfo, keepExisting, suppressEvent){
16711 if(nodeInfo instanceof Array){
16713 this.clearSelections(true);
16715 for(var i = 0, len = nodeInfo.length; i < len; i++){
16716 this.select(nodeInfo[i], true, true);
16720 var node = this.getNode(nodeInfo);
16721 if(!node || this.isSelected(node)){
16722 return; // already selected.
16725 this.clearSelections(true);
16728 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16729 Roo.fly(node).addClass(this.selectedClass);
16730 this.selections.push(node);
16731 if(!suppressEvent){
16732 this.fireEvent("selectionchange", this, this.selections);
16740 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
16741 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16742 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16744 unselect : function(nodeInfo, keepExisting, suppressEvent)
16746 if(nodeInfo instanceof Array){
16747 Roo.each(this.selections, function(s) {
16748 this.unselect(s, nodeInfo);
16752 var node = this.getNode(nodeInfo);
16753 if(!node || !this.isSelected(node)){
16754 //Roo.log("not selected");
16755 return; // not selected.
16759 Roo.each(this.selections, function(s) {
16761 Roo.fly(node).removeClass(this.selectedClass);
16768 this.selections= ns;
16769 this.fireEvent("selectionchange", this, this.selections);
16773 * Gets a template node.
16774 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16775 * @return {HTMLElement} The node or null if it wasn't found
16777 getNode : function(nodeInfo){
16778 if(typeof nodeInfo == "string"){
16779 return document.getElementById(nodeInfo);
16780 }else if(typeof nodeInfo == "number"){
16781 return this.nodes[nodeInfo];
16787 * Gets a range template nodes.
16788 * @param {Number} startIndex
16789 * @param {Number} endIndex
16790 * @return {Array} An array of nodes
16792 getNodes : function(start, end){
16793 var ns = this.nodes;
16794 start = start || 0;
16795 end = typeof end == "undefined" ? ns.length - 1 : end;
16798 for(var i = start; i <= end; i++){
16802 for(var i = start; i >= end; i--){
16810 * Finds the index of the passed node
16811 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16812 * @return {Number} The index of the node or -1
16814 indexOf : function(node){
16815 node = this.getNode(node);
16816 if(typeof node.nodeIndex == "number"){
16817 return node.nodeIndex;
16819 var ns = this.nodes;
16820 for(var i = 0, len = ns.length; i < len; i++){
16831 * based on jquery fullcalendar
16835 Roo.bootstrap = Roo.bootstrap || {};
16837 * @class Roo.bootstrap.Calendar
16838 * @extends Roo.bootstrap.Component
16839 * Bootstrap Calendar class
16840 * @cfg {Boolean} loadMask (true|false) default false
16841 * @cfg {Object} header generate the user specific header of the calendar, default false
16844 * Create a new Container
16845 * @param {Object} config The config object
16850 Roo.bootstrap.Calendar = function(config){
16851 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16855 * Fires when a date is selected
16856 * @param {DatePicker} this
16857 * @param {Date} date The selected date
16861 * @event monthchange
16862 * Fires when the displayed month changes
16863 * @param {DatePicker} this
16864 * @param {Date} date The selected month
16866 'monthchange': true,
16868 * @event evententer
16869 * Fires when mouse over an event
16870 * @param {Calendar} this
16871 * @param {event} Event
16873 'evententer': true,
16875 * @event eventleave
16876 * Fires when the mouse leaves an
16877 * @param {Calendar} this
16880 'eventleave': true,
16882 * @event eventclick
16883 * Fires when the mouse click an
16884 * @param {Calendar} this
16893 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16896 * @cfg {Number} startDay
16897 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16905 getAutoCreate : function(){
16908 var fc_button = function(name, corner, style, content ) {
16909 return Roo.apply({},{
16911 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16913 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16916 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16927 style : 'width:100%',
16934 cls : 'fc-header-left',
16936 fc_button('prev', 'left', 'arrow', '‹' ),
16937 fc_button('next', 'right', 'arrow', '›' ),
16938 { tag: 'span', cls: 'fc-header-space' },
16939 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16947 cls : 'fc-header-center',
16951 cls: 'fc-header-title',
16954 html : 'month / year'
16962 cls : 'fc-header-right',
16964 /* fc_button('month', 'left', '', 'month' ),
16965 fc_button('week', '', '', 'week' ),
16966 fc_button('day', 'right', '', 'day' )
16978 header = this.header;
16981 var cal_heads = function() {
16983 // fixme - handle this.
16985 for (var i =0; i < Date.dayNames.length; i++) {
16986 var d = Date.dayNames[i];
16989 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16990 html : d.substring(0,3)
16994 ret[0].cls += ' fc-first';
16995 ret[6].cls += ' fc-last';
16998 var cal_cell = function(n) {
17001 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17006 cls: 'fc-day-number',
17010 cls: 'fc-day-content',
17014 style: 'position: relative;' // height: 17px;
17026 var cal_rows = function() {
17029 for (var r = 0; r < 6; r++) {
17036 for (var i =0; i < Date.dayNames.length; i++) {
17037 var d = Date.dayNames[i];
17038 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17041 row.cn[0].cls+=' fc-first';
17042 row.cn[0].cn[0].style = 'min-height:90px';
17043 row.cn[6].cls+=' fc-last';
17047 ret[0].cls += ' fc-first';
17048 ret[4].cls += ' fc-prev-last';
17049 ret[5].cls += ' fc-last';
17056 cls: 'fc-border-separate',
17057 style : 'width:100%',
17065 cls : 'fc-first fc-last',
17083 cls : 'fc-content',
17084 style : "position: relative;",
17087 cls : 'fc-view fc-view-month fc-grid',
17088 style : 'position: relative',
17089 unselectable : 'on',
17092 cls : 'fc-event-container',
17093 style : 'position:absolute;z-index:8;top:0;left:0;'
17111 initEvents : function()
17114 throw "can not find store for calendar";
17120 style: "text-align:center",
17124 style: "background-color:white;width:50%;margin:250 auto",
17128 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17139 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17141 var size = this.el.select('.fc-content', true).first().getSize();
17142 this.maskEl.setSize(size.width, size.height);
17143 this.maskEl.enableDisplayMode("block");
17144 if(!this.loadMask){
17145 this.maskEl.hide();
17148 this.store = Roo.factory(this.store, Roo.data);
17149 this.store.on('load', this.onLoad, this);
17150 this.store.on('beforeload', this.onBeforeLoad, this);
17154 this.cells = this.el.select('.fc-day',true);
17155 //Roo.log(this.cells);
17156 this.textNodes = this.el.query('.fc-day-number');
17157 this.cells.addClassOnOver('fc-state-hover');
17159 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17160 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17161 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17162 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17164 this.on('monthchange', this.onMonthChange, this);
17166 this.update(new Date().clearTime());
17169 resize : function() {
17170 var sz = this.el.getSize();
17172 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17173 this.el.select('.fc-day-content div',true).setHeight(34);
17178 showPrevMonth : function(e){
17179 this.update(this.activeDate.add("mo", -1));
17181 showToday : function(e){
17182 this.update(new Date().clearTime());
17185 showNextMonth : function(e){
17186 this.update(this.activeDate.add("mo", 1));
17190 showPrevYear : function(){
17191 this.update(this.activeDate.add("y", -1));
17195 showNextYear : function(){
17196 this.update(this.activeDate.add("y", 1));
17201 update : function(date)
17203 var vd = this.activeDate;
17204 this.activeDate = date;
17205 // if(vd && this.el){
17206 // var t = date.getTime();
17207 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17208 // Roo.log('using add remove');
17210 // this.fireEvent('monthchange', this, date);
17212 // this.cells.removeClass("fc-state-highlight");
17213 // this.cells.each(function(c){
17214 // if(c.dateValue == t){
17215 // c.addClass("fc-state-highlight");
17216 // setTimeout(function(){
17217 // try{c.dom.firstChild.focus();}catch(e){}
17227 var days = date.getDaysInMonth();
17229 var firstOfMonth = date.getFirstDateOfMonth();
17230 var startingPos = firstOfMonth.getDay()-this.startDay;
17232 if(startingPos < this.startDay){
17236 var pm = date.add(Date.MONTH, -1);
17237 var prevStart = pm.getDaysInMonth()-startingPos;
17239 this.cells = this.el.select('.fc-day',true);
17240 this.textNodes = this.el.query('.fc-day-number');
17241 this.cells.addClassOnOver('fc-state-hover');
17243 var cells = this.cells.elements;
17244 var textEls = this.textNodes;
17246 Roo.each(cells, function(cell){
17247 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17250 days += startingPos;
17252 // convert everything to numbers so it's fast
17253 var day = 86400000;
17254 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17257 //Roo.log(prevStart);
17259 var today = new Date().clearTime().getTime();
17260 var sel = date.clearTime().getTime();
17261 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17262 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17263 var ddMatch = this.disabledDatesRE;
17264 var ddText = this.disabledDatesText;
17265 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17266 var ddaysText = this.disabledDaysText;
17267 var format = this.format;
17269 var setCellClass = function(cal, cell){
17273 //Roo.log('set Cell Class');
17275 var t = d.getTime();
17279 cell.dateValue = t;
17281 cell.className += " fc-today";
17282 cell.className += " fc-state-highlight";
17283 cell.title = cal.todayText;
17286 // disable highlight in other month..
17287 //cell.className += " fc-state-highlight";
17292 cell.className = " fc-state-disabled";
17293 cell.title = cal.minText;
17297 cell.className = " fc-state-disabled";
17298 cell.title = cal.maxText;
17302 if(ddays.indexOf(d.getDay()) != -1){
17303 cell.title = ddaysText;
17304 cell.className = " fc-state-disabled";
17307 if(ddMatch && format){
17308 var fvalue = d.dateFormat(format);
17309 if(ddMatch.test(fvalue)){
17310 cell.title = ddText.replace("%0", fvalue);
17311 cell.className = " fc-state-disabled";
17315 if (!cell.initialClassName) {
17316 cell.initialClassName = cell.dom.className;
17319 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17324 for(; i < startingPos; i++) {
17325 textEls[i].innerHTML = (++prevStart);
17326 d.setDate(d.getDate()+1);
17328 cells[i].className = "fc-past fc-other-month";
17329 setCellClass(this, cells[i]);
17334 for(; i < days; i++){
17335 intDay = i - startingPos + 1;
17336 textEls[i].innerHTML = (intDay);
17337 d.setDate(d.getDate()+1);
17339 cells[i].className = ''; // "x-date-active";
17340 setCellClass(this, cells[i]);
17344 for(; i < 42; i++) {
17345 textEls[i].innerHTML = (++extraDays);
17346 d.setDate(d.getDate()+1);
17348 cells[i].className = "fc-future fc-other-month";
17349 setCellClass(this, cells[i]);
17352 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17354 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17356 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17357 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17359 if(totalRows != 6){
17360 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17361 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17364 this.fireEvent('monthchange', this, date);
17368 if(!this.internalRender){
17369 var main = this.el.dom.firstChild;
17370 var w = main.offsetWidth;
17371 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17372 Roo.fly(main).setWidth(w);
17373 this.internalRender = true;
17374 // opera does not respect the auto grow header center column
17375 // then, after it gets a width opera refuses to recalculate
17376 // without a second pass
17377 if(Roo.isOpera && !this.secondPass){
17378 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17379 this.secondPass = true;
17380 this.update.defer(10, this, [date]);
17387 findCell : function(dt) {
17388 dt = dt.clearTime().getTime();
17390 this.cells.each(function(c){
17391 //Roo.log("check " +c.dateValue + '?=' + dt);
17392 if(c.dateValue == dt){
17402 findCells : function(ev) {
17403 var s = ev.start.clone().clearTime().getTime();
17405 var e= ev.end.clone().clearTime().getTime();
17408 this.cells.each(function(c){
17409 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17411 if(c.dateValue > e){
17414 if(c.dateValue < s){
17423 // findBestRow: function(cells)
17427 // for (var i =0 ; i < cells.length;i++) {
17428 // ret = Math.max(cells[i].rows || 0,ret);
17435 addItem : function(ev)
17437 // look for vertical location slot in
17438 var cells = this.findCells(ev);
17440 // ev.row = this.findBestRow(cells);
17442 // work out the location.
17446 for(var i =0; i < cells.length; i++) {
17448 cells[i].row = cells[0].row;
17451 cells[i].row = cells[i].row + 1;
17461 if (crow.start.getY() == cells[i].getY()) {
17463 crow.end = cells[i];
17480 cells[0].events.push(ev);
17482 this.calevents.push(ev);
17485 clearEvents: function() {
17487 if(!this.calevents){
17491 Roo.each(this.cells.elements, function(c){
17497 Roo.each(this.calevents, function(e) {
17498 Roo.each(e.els, function(el) {
17499 el.un('mouseenter' ,this.onEventEnter, this);
17500 el.un('mouseleave' ,this.onEventLeave, this);
17505 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17511 renderEvents: function()
17515 this.cells.each(function(c) {
17524 if(c.row != c.events.length){
17525 r = 4 - (4 - (c.row - c.events.length));
17528 c.events = ev.slice(0, r);
17529 c.more = ev.slice(r);
17531 if(c.more.length && c.more.length == 1){
17532 c.events.push(c.more.pop());
17535 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17539 this.cells.each(function(c) {
17541 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17544 for (var e = 0; e < c.events.length; e++){
17545 var ev = c.events[e];
17546 var rows = ev.rows;
17548 for(var i = 0; i < rows.length; i++) {
17550 // how many rows should it span..
17553 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17554 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17556 unselectable : "on",
17559 cls: 'fc-event-inner',
17563 // cls: 'fc-event-time',
17564 // html : cells.length > 1 ? '' : ev.time
17568 cls: 'fc-event-title',
17569 html : String.format('{0}', ev.title)
17576 cls: 'ui-resizable-handle ui-resizable-e',
17577 html : '  '
17584 cfg.cls += ' fc-event-start';
17586 if ((i+1) == rows.length) {
17587 cfg.cls += ' fc-event-end';
17590 var ctr = _this.el.select('.fc-event-container',true).first();
17591 var cg = ctr.createChild(cfg);
17593 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17594 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17596 var r = (c.more.length) ? 1 : 0;
17597 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17598 cg.setWidth(ebox.right - sbox.x -2);
17600 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17601 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17602 cg.on('click', _this.onEventClick, _this, ev);
17613 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17614 style : 'position: absolute',
17615 unselectable : "on",
17618 cls: 'fc-event-inner',
17622 cls: 'fc-event-title',
17630 cls: 'ui-resizable-handle ui-resizable-e',
17631 html : '  '
17637 var ctr = _this.el.select('.fc-event-container',true).first();
17638 var cg = ctr.createChild(cfg);
17640 var sbox = c.select('.fc-day-content',true).first().getBox();
17641 var ebox = c.select('.fc-day-content',true).first().getBox();
17643 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17644 cg.setWidth(ebox.right - sbox.x -2);
17646 cg.on('click', _this.onMoreEventClick, _this, c.more);
17656 onEventEnter: function (e, el,event,d) {
17657 this.fireEvent('evententer', this, el, event);
17660 onEventLeave: function (e, el,event,d) {
17661 this.fireEvent('eventleave', this, el, event);
17664 onEventClick: function (e, el,event,d) {
17665 this.fireEvent('eventclick', this, el, event);
17668 onMonthChange: function () {
17672 onMoreEventClick: function(e, el, more)
17676 this.calpopover.placement = 'right';
17677 this.calpopover.setTitle('More');
17679 this.calpopover.setContent('');
17681 var ctr = this.calpopover.el.select('.popover-content', true).first();
17683 Roo.each(more, function(m){
17685 cls : 'fc-event-hori fc-event-draggable',
17688 var cg = ctr.createChild(cfg);
17690 cg.on('click', _this.onEventClick, _this, m);
17693 this.calpopover.show(el);
17698 onLoad: function ()
17700 this.calevents = [];
17703 if(this.store.getCount() > 0){
17704 this.store.data.each(function(d){
17707 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17708 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17709 time : d.data.start_time,
17710 title : d.data.title,
17711 description : d.data.description,
17712 venue : d.data.venue
17717 this.renderEvents();
17719 if(this.calevents.length && this.loadMask){
17720 this.maskEl.hide();
17724 onBeforeLoad: function()
17726 this.clearEvents();
17728 this.maskEl.show();
17742 * @class Roo.bootstrap.Popover
17743 * @extends Roo.bootstrap.Component
17744 * Bootstrap Popover class
17745 * @cfg {String} html contents of the popover (or false to use children..)
17746 * @cfg {String} title of popover (or false to hide)
17747 * @cfg {String} placement how it is placed
17748 * @cfg {String} trigger click || hover (or false to trigger manually)
17749 * @cfg {String} over what (parent or false to trigger manually.)
17750 * @cfg {Number} delay - delay before showing
17753 * Create a new Popover
17754 * @param {Object} config The config object
17757 Roo.bootstrap.Popover = function(config){
17758 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17764 * After the popover show
17766 * @param {Roo.bootstrap.Popover} this
17771 * After the popover hide
17773 * @param {Roo.bootstrap.Popover} this
17779 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17781 title: 'Fill in a title',
17784 placement : 'right',
17785 trigger : 'hover', // hover
17791 can_build_overlaid : false,
17793 getChildContainer : function()
17795 return this.el.select('.popover-content',true).first();
17798 getAutoCreate : function(){
17801 cls : 'popover roo-dynamic',
17802 style: 'display:block',
17808 cls : 'popover-inner',
17812 cls: 'popover-title popover-header',
17816 cls : 'popover-content popover-body',
17827 setTitle: function(str)
17830 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17832 setContent: function(str)
17835 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17837 // as it get's added to the bottom of the page.
17838 onRender : function(ct, position)
17840 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17842 var cfg = Roo.apply({}, this.getAutoCreate());
17846 cfg.cls += ' ' + this.cls;
17849 cfg.style = this.style;
17851 //Roo.log("adding to ");
17852 this.el = Roo.get(document.body).createChild(cfg, position);
17853 // Roo.log(this.el);
17858 initEvents : function()
17860 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17861 this.el.enableDisplayMode('block');
17863 if (this.over === false) {
17866 if (this.triggers === false) {
17869 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17870 var triggers = this.trigger ? this.trigger.split(' ') : [];
17871 Roo.each(triggers, function(trigger) {
17873 if (trigger == 'click') {
17874 on_el.on('click', this.toggle, this);
17875 } else if (trigger != 'manual') {
17876 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17877 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17879 on_el.on(eventIn ,this.enter, this);
17880 on_el.on(eventOut, this.leave, this);
17891 toggle : function () {
17892 this.hoverState == 'in' ? this.leave() : this.enter();
17895 enter : function () {
17897 clearTimeout(this.timeout);
17899 this.hoverState = 'in';
17901 if (!this.delay || !this.delay.show) {
17906 this.timeout = setTimeout(function () {
17907 if (_t.hoverState == 'in') {
17910 }, this.delay.show)
17913 leave : function() {
17914 clearTimeout(this.timeout);
17916 this.hoverState = 'out';
17918 if (!this.delay || !this.delay.hide) {
17923 this.timeout = setTimeout(function () {
17924 if (_t.hoverState == 'out') {
17927 }, this.delay.hide)
17930 show : function (on_el)
17933 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17937 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17938 if (this.html !== false) {
17939 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17941 this.el.removeClass([
17942 'fade','top','bottom', 'left', 'right','in',
17943 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17945 if (!this.title.length) {
17946 this.el.select('.popover-title',true).hide();
17949 var placement = typeof this.placement == 'function' ?
17950 this.placement.call(this, this.el, on_el) :
17953 var autoToken = /\s?auto?\s?/i;
17954 var autoPlace = autoToken.test(placement);
17956 placement = placement.replace(autoToken, '') || 'top';
17960 //this.el.setXY([0,0]);
17962 this.el.dom.style.display='block';
17963 this.el.addClass(placement);
17965 //this.el.appendTo(on_el);
17967 var p = this.getPosition();
17968 var box = this.el.getBox();
17973 var align = Roo.bootstrap.Popover.alignment[placement];
17976 this.el.alignTo(on_el, align[0],align[1]);
17977 //var arrow = this.el.select('.arrow',true).first();
17978 //arrow.set(align[2],
17980 this.el.addClass('in');
17983 if (this.el.hasClass('fade')) {
17987 this.hoverState = 'in';
17989 this.fireEvent('show', this);
17994 this.el.setXY([0,0]);
17995 this.el.removeClass('in');
17997 this.hoverState = null;
17999 this.fireEvent('hide', this);
18004 Roo.bootstrap.Popover.alignment = {
18005 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18006 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18007 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18008 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18019 * @class Roo.bootstrap.Progress
18020 * @extends Roo.bootstrap.Component
18021 * Bootstrap Progress class
18022 * @cfg {Boolean} striped striped of the progress bar
18023 * @cfg {Boolean} active animated of the progress bar
18027 * Create a new Progress
18028 * @param {Object} config The config object
18031 Roo.bootstrap.Progress = function(config){
18032 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18035 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18040 getAutoCreate : function(){
18048 cfg.cls += ' progress-striped';
18052 cfg.cls += ' active';
18071 * @class Roo.bootstrap.ProgressBar
18072 * @extends Roo.bootstrap.Component
18073 * Bootstrap ProgressBar class
18074 * @cfg {Number} aria_valuenow aria-value now
18075 * @cfg {Number} aria_valuemin aria-value min
18076 * @cfg {Number} aria_valuemax aria-value max
18077 * @cfg {String} label label for the progress bar
18078 * @cfg {String} panel (success | info | warning | danger )
18079 * @cfg {String} role role of the progress bar
18080 * @cfg {String} sr_only text
18084 * Create a new ProgressBar
18085 * @param {Object} config The config object
18088 Roo.bootstrap.ProgressBar = function(config){
18089 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18092 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18096 aria_valuemax : 100,
18102 getAutoCreate : function()
18107 cls: 'progress-bar',
18108 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18120 cfg.role = this.role;
18123 if(this.aria_valuenow){
18124 cfg['aria-valuenow'] = this.aria_valuenow;
18127 if(this.aria_valuemin){
18128 cfg['aria-valuemin'] = this.aria_valuemin;
18131 if(this.aria_valuemax){
18132 cfg['aria-valuemax'] = this.aria_valuemax;
18135 if(this.label && !this.sr_only){
18136 cfg.html = this.label;
18140 cfg.cls += ' progress-bar-' + this.panel;
18146 update : function(aria_valuenow)
18148 this.aria_valuenow = aria_valuenow;
18150 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18165 * @class Roo.bootstrap.TabGroup
18166 * @extends Roo.bootstrap.Column
18167 * Bootstrap Column class
18168 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18169 * @cfg {Boolean} carousel true to make the group behave like a carousel
18170 * @cfg {Boolean} bullets show bullets for the panels
18171 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18172 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18173 * @cfg {Boolean} showarrow (true|false) show arrow default true
18176 * Create a new TabGroup
18177 * @param {Object} config The config object
18180 Roo.bootstrap.TabGroup = function(config){
18181 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18183 this.navId = Roo.id();
18186 Roo.bootstrap.TabGroup.register(this);
18190 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18193 transition : false,
18198 slideOnTouch : false,
18201 getAutoCreate : function()
18203 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18205 cfg.cls += ' tab-content';
18207 if (this.carousel) {
18208 cfg.cls += ' carousel slide';
18211 cls : 'carousel-inner',
18215 if(this.bullets && !Roo.isTouch){
18218 cls : 'carousel-bullets',
18222 if(this.bullets_cls){
18223 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18230 cfg.cn[0].cn.push(bullets);
18233 if(this.showarrow){
18234 cfg.cn[0].cn.push({
18236 class : 'carousel-arrow',
18240 class : 'carousel-prev',
18244 class : 'fa fa-chevron-left'
18250 class : 'carousel-next',
18254 class : 'fa fa-chevron-right'
18267 initEvents: function()
18269 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18270 // this.el.on("touchstart", this.onTouchStart, this);
18273 if(this.autoslide){
18276 this.slideFn = window.setInterval(function() {
18277 _this.showPanelNext();
18281 if(this.showarrow){
18282 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18283 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18289 // onTouchStart : function(e, el, o)
18291 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18295 // this.showPanelNext();
18299 getChildContainer : function()
18301 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18305 * register a Navigation item
18306 * @param {Roo.bootstrap.NavItem} the navitem to add
18308 register : function(item)
18310 this.tabs.push( item);
18311 item.navId = this.navId; // not really needed..
18316 getActivePanel : function()
18319 Roo.each(this.tabs, function(t) {
18329 getPanelByName : function(n)
18332 Roo.each(this.tabs, function(t) {
18333 if (t.tabId == n) {
18341 indexOfPanel : function(p)
18344 Roo.each(this.tabs, function(t,i) {
18345 if (t.tabId == p.tabId) {
18354 * show a specific panel
18355 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18356 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18358 showPanel : function (pan)
18360 if(this.transition || typeof(pan) == 'undefined'){
18361 Roo.log("waiting for the transitionend");
18365 if (typeof(pan) == 'number') {
18366 pan = this.tabs[pan];
18369 if (typeof(pan) == 'string') {
18370 pan = this.getPanelByName(pan);
18373 var cur = this.getActivePanel();
18376 Roo.log('pan or acitve pan is undefined');
18380 if (pan.tabId == this.getActivePanel().tabId) {
18384 if (false === cur.fireEvent('beforedeactivate')) {
18388 if(this.bullets > 0 && !Roo.isTouch){
18389 this.setActiveBullet(this.indexOfPanel(pan));
18392 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18394 //class="carousel-item carousel-item-next carousel-item-left"
18396 this.transition = true;
18397 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18398 var lr = dir == 'next' ? 'left' : 'right';
18399 pan.el.addClass(dir); // or prev
18400 pan.el.addClass('carousel-item-' + dir); // or prev
18401 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18402 cur.el.addClass(lr); // or right
18403 pan.el.addClass(lr);
18404 cur.el.addClass('carousel-item-' +lr); // or right
18405 pan.el.addClass('carousel-item-' +lr);
18409 cur.el.on('transitionend', function() {
18410 Roo.log("trans end?");
18412 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18413 pan.setActive(true);
18415 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18416 cur.setActive(false);
18418 _this.transition = false;
18420 }, this, { single: true } );
18425 cur.setActive(false);
18426 pan.setActive(true);
18431 showPanelNext : function()
18433 var i = this.indexOfPanel(this.getActivePanel());
18435 if (i >= this.tabs.length - 1 && !this.autoslide) {
18439 if (i >= this.tabs.length - 1 && this.autoslide) {
18443 this.showPanel(this.tabs[i+1]);
18446 showPanelPrev : function()
18448 var i = this.indexOfPanel(this.getActivePanel());
18450 if (i < 1 && !this.autoslide) {
18454 if (i < 1 && this.autoslide) {
18455 i = this.tabs.length;
18458 this.showPanel(this.tabs[i-1]);
18462 addBullet: function()
18464 if(!this.bullets || Roo.isTouch){
18467 var ctr = this.el.select('.carousel-bullets',true).first();
18468 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18469 var bullet = ctr.createChild({
18470 cls : 'bullet bullet-' + i
18471 },ctr.dom.lastChild);
18476 bullet.on('click', (function(e, el, o, ii, t){
18478 e.preventDefault();
18480 this.showPanel(ii);
18482 if(this.autoslide && this.slideFn){
18483 clearInterval(this.slideFn);
18484 this.slideFn = window.setInterval(function() {
18485 _this.showPanelNext();
18489 }).createDelegate(this, [i, bullet], true));
18494 setActiveBullet : function(i)
18500 Roo.each(this.el.select('.bullet', true).elements, function(el){
18501 el.removeClass('selected');
18504 var bullet = this.el.select('.bullet-' + i, true).first();
18510 bullet.addClass('selected');
18521 Roo.apply(Roo.bootstrap.TabGroup, {
18525 * register a Navigation Group
18526 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18528 register : function(navgrp)
18530 this.groups[navgrp.navId] = navgrp;
18534 * fetch a Navigation Group based on the navigation ID
18535 * if one does not exist , it will get created.
18536 * @param {string} the navgroup to add
18537 * @returns {Roo.bootstrap.NavGroup} the navgroup
18539 get: function(navId) {
18540 if (typeof(this.groups[navId]) == 'undefined') {
18541 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18543 return this.groups[navId] ;
18558 * @class Roo.bootstrap.TabPanel
18559 * @extends Roo.bootstrap.Component
18560 * Bootstrap TabPanel class
18561 * @cfg {Boolean} active panel active
18562 * @cfg {String} html panel content
18563 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18564 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18565 * @cfg {String} href click to link..
18569 * Create a new TabPanel
18570 * @param {Object} config The config object
18573 Roo.bootstrap.TabPanel = function(config){
18574 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18578 * Fires when the active status changes
18579 * @param {Roo.bootstrap.TabPanel} this
18580 * @param {Boolean} state the new state
18585 * @event beforedeactivate
18586 * Fires before a tab is de-activated - can be used to do validation on a form.
18587 * @param {Roo.bootstrap.TabPanel} this
18588 * @return {Boolean} false if there is an error
18591 'beforedeactivate': true
18594 this.tabId = this.tabId || Roo.id();
18598 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18606 getAutoCreate : function(){
18611 // item is needed for carousel - not sure if it has any effect otherwise
18612 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18613 html: this.html || ''
18617 cfg.cls += ' active';
18621 cfg.tabId = this.tabId;
18629 initEvents: function()
18631 var p = this.parent();
18633 this.navId = this.navId || p.navId;
18635 if (typeof(this.navId) != 'undefined') {
18636 // not really needed.. but just in case.. parent should be a NavGroup.
18637 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18641 var i = tg.tabs.length - 1;
18643 if(this.active && tg.bullets > 0 && i < tg.bullets){
18644 tg.setActiveBullet(i);
18648 this.el.on('click', this.onClick, this);
18651 this.el.on("touchstart", this.onTouchStart, this);
18652 this.el.on("touchmove", this.onTouchMove, this);
18653 this.el.on("touchend", this.onTouchEnd, this);
18658 onRender : function(ct, position)
18660 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18663 setActive : function(state)
18665 Roo.log("panel - set active " + this.tabId + "=" + state);
18667 this.active = state;
18669 this.el.removeClass('active');
18671 } else if (!this.el.hasClass('active')) {
18672 this.el.addClass('active');
18675 this.fireEvent('changed', this, state);
18678 onClick : function(e)
18680 e.preventDefault();
18682 if(!this.href.length){
18686 window.location.href = this.href;
18695 onTouchStart : function(e)
18697 this.swiping = false;
18699 this.startX = e.browserEvent.touches[0].clientX;
18700 this.startY = e.browserEvent.touches[0].clientY;
18703 onTouchMove : function(e)
18705 this.swiping = true;
18707 this.endX = e.browserEvent.touches[0].clientX;
18708 this.endY = e.browserEvent.touches[0].clientY;
18711 onTouchEnd : function(e)
18718 var tabGroup = this.parent();
18720 if(this.endX > this.startX){ // swiping right
18721 tabGroup.showPanelPrev();
18725 if(this.startX > this.endX){ // swiping left
18726 tabGroup.showPanelNext();
18745 * @class Roo.bootstrap.DateField
18746 * @extends Roo.bootstrap.Input
18747 * Bootstrap DateField class
18748 * @cfg {Number} weekStart default 0
18749 * @cfg {String} viewMode default empty, (months|years)
18750 * @cfg {String} minViewMode default empty, (months|years)
18751 * @cfg {Number} startDate default -Infinity
18752 * @cfg {Number} endDate default Infinity
18753 * @cfg {Boolean} todayHighlight default false
18754 * @cfg {Boolean} todayBtn default false
18755 * @cfg {Boolean} calendarWeeks default false
18756 * @cfg {Object} daysOfWeekDisabled default empty
18757 * @cfg {Boolean} singleMode default false (true | false)
18759 * @cfg {Boolean} keyboardNavigation default true
18760 * @cfg {String} language default en
18763 * Create a new DateField
18764 * @param {Object} config The config object
18767 Roo.bootstrap.DateField = function(config){
18768 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18772 * Fires when this field show.
18773 * @param {Roo.bootstrap.DateField} this
18774 * @param {Mixed} date The date value
18779 * Fires when this field hide.
18780 * @param {Roo.bootstrap.DateField} this
18781 * @param {Mixed} date The date value
18786 * Fires when select a date.
18787 * @param {Roo.bootstrap.DateField} this
18788 * @param {Mixed} date The date value
18792 * @event beforeselect
18793 * Fires when before select a date.
18794 * @param {Roo.bootstrap.DateField} this
18795 * @param {Mixed} date The date value
18797 beforeselect : true
18801 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18804 * @cfg {String} format
18805 * The default date format string which can be overriden for localization support. The format must be
18806 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18810 * @cfg {String} altFormats
18811 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18812 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18814 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18822 todayHighlight : false,
18828 keyboardNavigation: true,
18830 calendarWeeks: false,
18832 startDate: -Infinity,
18836 daysOfWeekDisabled: [],
18840 singleMode : false,
18842 UTCDate: function()
18844 return new Date(Date.UTC.apply(Date, arguments));
18847 UTCToday: function()
18849 var today = new Date();
18850 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18853 getDate: function() {
18854 var d = this.getUTCDate();
18855 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18858 getUTCDate: function() {
18862 setDate: function(d) {
18863 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18866 setUTCDate: function(d) {
18868 this.setValue(this.formatDate(this.date));
18871 onRender: function(ct, position)
18874 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18876 this.language = this.language || 'en';
18877 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18878 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18880 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18881 this.format = this.format || 'm/d/y';
18882 this.isInline = false;
18883 this.isInput = true;
18884 this.component = this.el.select('.add-on', true).first() || false;
18885 this.component = (this.component && this.component.length === 0) ? false : this.component;
18886 this.hasInput = this.component && this.inputEl().length;
18888 if (typeof(this.minViewMode === 'string')) {
18889 switch (this.minViewMode) {
18891 this.minViewMode = 1;
18894 this.minViewMode = 2;
18897 this.minViewMode = 0;
18902 if (typeof(this.viewMode === 'string')) {
18903 switch (this.viewMode) {
18916 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18918 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18920 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18922 this.picker().on('mousedown', this.onMousedown, this);
18923 this.picker().on('click', this.onClick, this);
18925 this.picker().addClass('datepicker-dropdown');
18927 this.startViewMode = this.viewMode;
18929 if(this.singleMode){
18930 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18931 v.setVisibilityMode(Roo.Element.DISPLAY);
18935 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18936 v.setStyle('width', '189px');
18940 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18941 if(!this.calendarWeeks){
18946 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18947 v.attr('colspan', function(i, val){
18948 return parseInt(val) + 1;
18953 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18955 this.setStartDate(this.startDate);
18956 this.setEndDate(this.endDate);
18958 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18965 if(this.isInline) {
18970 picker : function()
18972 return this.pickerEl;
18973 // return this.el.select('.datepicker', true).first();
18976 fillDow: function()
18978 var dowCnt = this.weekStart;
18987 if(this.calendarWeeks){
18995 while (dowCnt < this.weekStart + 7) {
18999 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19003 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19006 fillMonths: function()
19009 var months = this.picker().select('>.datepicker-months td', true).first();
19011 months.dom.innerHTML = '';
19017 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19020 months.createChild(month);
19027 this.date = (typeof(this.date) === 'undefined' || ((typeof(this.date) === 'string') && !this.date.length)) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
19029 if (this.date < this.startDate) {
19030 this.viewDate = new Date(this.startDate);
19031 } else if (this.date > this.endDate) {
19032 this.viewDate = new Date(this.endDate);
19034 this.viewDate = new Date(this.date);
19042 var d = new Date(this.viewDate),
19043 year = d.getUTCFullYear(),
19044 month = d.getUTCMonth(),
19045 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19046 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19047 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19048 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19049 currentDate = this.date && this.date.valueOf(),
19050 today = this.UTCToday();
19052 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19054 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19056 // this.picker.select('>tfoot th.today').
19057 // .text(dates[this.language].today)
19058 // .toggle(this.todayBtn !== false);
19060 this.updateNavArrows();
19063 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19065 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19067 prevMonth.setUTCDate(day);
19069 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19071 var nextMonth = new Date(prevMonth);
19073 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19075 nextMonth = nextMonth.valueOf();
19077 var fillMonths = false;
19079 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19081 while(prevMonth.valueOf() <= nextMonth) {
19084 if (prevMonth.getUTCDay() === this.weekStart) {
19086 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19094 if(this.calendarWeeks){
19095 // ISO 8601: First week contains first thursday.
19096 // ISO also states week starts on Monday, but we can be more abstract here.
19098 // Start of current week: based on weekstart/current date
19099 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19100 // Thursday of this week
19101 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19102 // First Thursday of year, year from thursday
19103 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19104 // Calendar week: ms between thursdays, div ms per day, div 7 days
19105 calWeek = (th - yth) / 864e5 / 7 + 1;
19107 fillMonths.cn.push({
19115 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19117 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19120 if (this.todayHighlight &&
19121 prevMonth.getUTCFullYear() == today.getFullYear() &&
19122 prevMonth.getUTCMonth() == today.getMonth() &&
19123 prevMonth.getUTCDate() == today.getDate()) {
19124 clsName += ' today';
19127 if (currentDate && prevMonth.valueOf() === currentDate) {
19128 clsName += ' active';
19131 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19132 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19133 clsName += ' disabled';
19136 fillMonths.cn.push({
19138 cls: 'day ' + clsName,
19139 html: prevMonth.getDate()
19142 prevMonth.setDate(prevMonth.getDate()+1);
19145 var currentYear = this.date && this.date.getUTCFullYear();
19146 var currentMonth = this.date && this.date.getUTCMonth();
19148 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19150 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19151 v.removeClass('active');
19153 if(currentYear === year && k === currentMonth){
19154 v.addClass('active');
19157 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19158 v.addClass('disabled');
19164 year = parseInt(year/10, 10) * 10;
19166 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19168 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19171 for (var i = -1; i < 11; i++) {
19172 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19174 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19182 showMode: function(dir)
19185 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19188 Roo.each(this.picker().select('>div',true).elements, function(v){
19189 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19192 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19197 if(this.isInline) {
19201 this.picker().removeClass(['bottom', 'top']);
19203 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19205 * place to the top of element!
19209 this.picker().addClass('top');
19210 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19215 this.picker().addClass('bottom');
19217 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19220 parseDate : function(value)
19222 if(!value || value instanceof Date){
19225 var v = Date.parseDate(value, this.format);
19226 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19227 v = Date.parseDate(value, 'Y-m-d');
19229 if(!v && this.altFormats){
19230 if(!this.altFormatsArray){
19231 this.altFormatsArray = this.altFormats.split("|");
19233 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19234 v = Date.parseDate(value, this.altFormatsArray[i]);
19240 formatDate : function(date, fmt)
19242 return (!date || !(date instanceof Date)) ?
19243 date : date.dateFormat(fmt || this.format);
19246 onFocus : function()
19248 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19252 onBlur : function()
19254 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19256 var d = this.inputEl().getValue();
19263 showPopup : function()
19265 this.picker().show();
19269 this.fireEvent('showpopup', this, this.date);
19272 hidePopup : function()
19274 if(this.isInline) {
19277 this.picker().hide();
19278 this.viewMode = this.startViewMode;
19281 this.fireEvent('hidepopup', this, this.date);
19285 onMousedown: function(e)
19287 e.stopPropagation();
19288 e.preventDefault();
19293 Roo.bootstrap.DateField.superclass.keyup.call(this);
19297 setValue: function(v)
19299 if(this.fireEvent('beforeselect', this, v) !== false){
19300 var d = new Date(this.parseDate(v) ).clearTime();
19302 if(isNaN(d.getTime())){
19303 this.date = this.viewDate = '';
19304 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19308 v = this.formatDate(d);
19310 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19312 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19316 this.fireEvent('select', this, this.date);
19320 getValue: function()
19322 return this.formatDate(this.date);
19325 fireKey: function(e)
19327 if (!this.picker().isVisible()){
19328 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19334 var dateChanged = false,
19336 newDate, newViewDate;
19341 e.preventDefault();
19345 if (!this.keyboardNavigation) {
19348 dir = e.keyCode == 37 ? -1 : 1;
19351 newDate = this.moveYear(this.date, dir);
19352 newViewDate = this.moveYear(this.viewDate, dir);
19353 } else if (e.shiftKey){
19354 newDate = this.moveMonth(this.date, dir);
19355 newViewDate = this.moveMonth(this.viewDate, dir);
19357 newDate = new Date(this.date);
19358 newDate.setUTCDate(this.date.getUTCDate() + dir);
19359 newViewDate = new Date(this.viewDate);
19360 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19362 if (this.dateWithinRange(newDate)){
19363 this.date = newDate;
19364 this.viewDate = newViewDate;
19365 this.setValue(this.formatDate(this.date));
19367 e.preventDefault();
19368 dateChanged = true;
19373 if (!this.keyboardNavigation) {
19376 dir = e.keyCode == 38 ? -1 : 1;
19378 newDate = this.moveYear(this.date, dir);
19379 newViewDate = this.moveYear(this.viewDate, dir);
19380 } else if (e.shiftKey){
19381 newDate = this.moveMonth(this.date, dir);
19382 newViewDate = this.moveMonth(this.viewDate, dir);
19384 newDate = new Date(this.date);
19385 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19386 newViewDate = new Date(this.viewDate);
19387 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19389 if (this.dateWithinRange(newDate)){
19390 this.date = newDate;
19391 this.viewDate = newViewDate;
19392 this.setValue(this.formatDate(this.date));
19394 e.preventDefault();
19395 dateChanged = true;
19399 this.setValue(this.formatDate(this.date));
19401 e.preventDefault();
19404 this.setValue(this.formatDate(this.date));
19418 onClick: function(e)
19420 e.stopPropagation();
19421 e.preventDefault();
19423 var target = e.getTarget();
19425 if(target.nodeName.toLowerCase() === 'i'){
19426 target = Roo.get(target).dom.parentNode;
19429 var nodeName = target.nodeName;
19430 var className = target.className;
19431 var html = target.innerHTML;
19432 //Roo.log(nodeName);
19434 switch(nodeName.toLowerCase()) {
19436 switch(className) {
19442 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19443 switch(this.viewMode){
19445 this.viewDate = this.moveMonth(this.viewDate, dir);
19449 this.viewDate = this.moveYear(this.viewDate, dir);
19455 var date = new Date();
19456 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19458 this.setValue(this.formatDate(this.date));
19465 if (className.indexOf('disabled') < 0) {
19466 this.viewDate.setUTCDate(1);
19467 if (className.indexOf('month') > -1) {
19468 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19470 var year = parseInt(html, 10) || 0;
19471 this.viewDate.setUTCFullYear(year);
19475 if(this.singleMode){
19476 this.setValue(this.formatDate(this.viewDate));
19487 //Roo.log(className);
19488 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19489 var day = parseInt(html, 10) || 1;
19490 var year = this.viewDate.getUTCFullYear(),
19491 month = this.viewDate.getUTCMonth();
19493 if (className.indexOf('old') > -1) {
19500 } else if (className.indexOf('new') > -1) {
19508 //Roo.log([year,month,day]);
19509 this.date = this.UTCDate(year, month, day,0,0,0,0);
19510 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19512 //Roo.log(this.formatDate(this.date));
19513 this.setValue(this.formatDate(this.date));
19520 setStartDate: function(startDate)
19522 this.startDate = startDate || -Infinity;
19523 if (this.startDate !== -Infinity) {
19524 this.startDate = this.parseDate(this.startDate);
19527 this.updateNavArrows();
19530 setEndDate: function(endDate)
19532 this.endDate = endDate || Infinity;
19533 if (this.endDate !== Infinity) {
19534 this.endDate = this.parseDate(this.endDate);
19537 this.updateNavArrows();
19540 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19542 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19543 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19544 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19546 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19547 return parseInt(d, 10);
19550 this.updateNavArrows();
19553 updateNavArrows: function()
19555 if(this.singleMode){
19559 var d = new Date(this.viewDate),
19560 year = d.getUTCFullYear(),
19561 month = d.getUTCMonth();
19563 Roo.each(this.picker().select('.prev', true).elements, function(v){
19565 switch (this.viewMode) {
19568 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19574 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19581 Roo.each(this.picker().select('.next', true).elements, function(v){
19583 switch (this.viewMode) {
19586 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19592 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19600 moveMonth: function(date, dir)
19605 var new_date = new Date(date.valueOf()),
19606 day = new_date.getUTCDate(),
19607 month = new_date.getUTCMonth(),
19608 mag = Math.abs(dir),
19610 dir = dir > 0 ? 1 : -1;
19613 // If going back one month, make sure month is not current month
19614 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19616 return new_date.getUTCMonth() == month;
19618 // If going forward one month, make sure month is as expected
19619 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19621 return new_date.getUTCMonth() != new_month;
19623 new_month = month + dir;
19624 new_date.setUTCMonth(new_month);
19625 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19626 if (new_month < 0 || new_month > 11) {
19627 new_month = (new_month + 12) % 12;
19630 // For magnitudes >1, move one month at a time...
19631 for (var i=0; i<mag; i++) {
19632 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19633 new_date = this.moveMonth(new_date, dir);
19635 // ...then reset the day, keeping it in the new month
19636 new_month = new_date.getUTCMonth();
19637 new_date.setUTCDate(day);
19639 return new_month != new_date.getUTCMonth();
19642 // Common date-resetting loop -- if date is beyond end of month, make it
19645 new_date.setUTCDate(--day);
19646 new_date.setUTCMonth(new_month);
19651 moveYear: function(date, dir)
19653 return this.moveMonth(date, dir*12);
19656 dateWithinRange: function(date)
19658 return date >= this.startDate && date <= this.endDate;
19664 this.picker().remove();
19667 validateValue : function(value)
19669 if(this.getVisibilityEl().hasClass('hidden')){
19673 if(value.length < 1) {
19674 if(this.allowBlank){
19680 if(value.length < this.minLength){
19683 if(value.length > this.maxLength){
19687 var vt = Roo.form.VTypes;
19688 if(!vt[this.vtype](value, this)){
19692 if(typeof this.validator == "function"){
19693 var msg = this.validator(value);
19699 if(this.regex && !this.regex.test(value)){
19703 if(typeof(this.parseDate(value)) == 'undefined'){
19707 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19711 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19721 this.date = this.viewDate = '';
19723 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19728 Roo.apply(Roo.bootstrap.DateField, {
19739 html: '<i class="fa fa-arrow-left"/>'
19749 html: '<i class="fa fa-arrow-right"/>'
19791 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19792 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19793 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19794 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19795 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19808 navFnc: 'FullYear',
19813 navFnc: 'FullYear',
19818 Roo.apply(Roo.bootstrap.DateField, {
19822 cls: 'datepicker dropdown-menu roo-dynamic',
19826 cls: 'datepicker-days',
19830 cls: 'table-condensed',
19832 Roo.bootstrap.DateField.head,
19836 Roo.bootstrap.DateField.footer
19843 cls: 'datepicker-months',
19847 cls: 'table-condensed',
19849 Roo.bootstrap.DateField.head,
19850 Roo.bootstrap.DateField.content,
19851 Roo.bootstrap.DateField.footer
19858 cls: 'datepicker-years',
19862 cls: 'table-condensed',
19864 Roo.bootstrap.DateField.head,
19865 Roo.bootstrap.DateField.content,
19866 Roo.bootstrap.DateField.footer
19885 * @class Roo.bootstrap.TimeField
19886 * @extends Roo.bootstrap.Input
19887 * Bootstrap DateField class
19891 * Create a new TimeField
19892 * @param {Object} config The config object
19895 Roo.bootstrap.TimeField = function(config){
19896 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19900 * Fires when this field show.
19901 * @param {Roo.bootstrap.DateField} thisthis
19902 * @param {Mixed} date The date value
19907 * Fires when this field hide.
19908 * @param {Roo.bootstrap.DateField} this
19909 * @param {Mixed} date The date value
19914 * Fires when select a date.
19915 * @param {Roo.bootstrap.DateField} this
19916 * @param {Mixed} date The date value
19922 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19925 * @cfg {String} format
19926 * The default time format string which can be overriden for localization support. The format must be
19927 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19931 onRender: function(ct, position)
19934 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19936 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19938 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19940 this.pop = this.picker().select('>.datepicker-time',true).first();
19941 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19943 this.picker().on('mousedown', this.onMousedown, this);
19944 this.picker().on('click', this.onClick, this);
19946 this.picker().addClass('datepicker-dropdown');
19951 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19952 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19953 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19954 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19955 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19956 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19960 fireKey: function(e){
19961 if (!this.picker().isVisible()){
19962 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19968 e.preventDefault();
19976 this.onTogglePeriod();
19979 this.onIncrementMinutes();
19982 this.onDecrementMinutes();
19991 onClick: function(e) {
19992 e.stopPropagation();
19993 e.preventDefault();
19996 picker : function()
19998 return this.el.select('.datepicker', true).first();
20001 fillTime: function()
20003 var time = this.pop.select('tbody', true).first();
20005 time.dom.innerHTML = '';
20020 cls: 'hours-up glyphicon glyphicon-chevron-up'
20040 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20061 cls: 'timepicker-hour',
20076 cls: 'timepicker-minute',
20091 cls: 'btn btn-primary period',
20113 cls: 'hours-down glyphicon glyphicon-chevron-down'
20133 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20151 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20158 var hours = this.time.getHours();
20159 var minutes = this.time.getMinutes();
20172 hours = hours - 12;
20176 hours = '0' + hours;
20180 minutes = '0' + minutes;
20183 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20184 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20185 this.pop.select('button', true).first().dom.innerHTML = period;
20191 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20193 var cls = ['bottom'];
20195 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20202 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20207 this.picker().addClass(cls.join('-'));
20211 Roo.each(cls, function(c){
20213 _this.picker().setTop(_this.inputEl().getHeight());
20217 _this.picker().setTop(0 - _this.picker().getHeight());
20222 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20226 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20233 onFocus : function()
20235 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20239 onBlur : function()
20241 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20247 this.picker().show();
20252 this.fireEvent('show', this, this.date);
20257 this.picker().hide();
20260 this.fireEvent('hide', this, this.date);
20263 setTime : function()
20266 this.setValue(this.time.format(this.format));
20268 this.fireEvent('select', this, this.date);
20273 onMousedown: function(e){
20274 e.stopPropagation();
20275 e.preventDefault();
20278 onIncrementHours: function()
20280 Roo.log('onIncrementHours');
20281 this.time = this.time.add(Date.HOUR, 1);
20286 onDecrementHours: function()
20288 Roo.log('onDecrementHours');
20289 this.time = this.time.add(Date.HOUR, -1);
20293 onIncrementMinutes: function()
20295 Roo.log('onIncrementMinutes');
20296 this.time = this.time.add(Date.MINUTE, 1);
20300 onDecrementMinutes: function()
20302 Roo.log('onDecrementMinutes');
20303 this.time = this.time.add(Date.MINUTE, -1);
20307 onTogglePeriod: function()
20309 Roo.log('onTogglePeriod');
20310 this.time = this.time.add(Date.HOUR, 12);
20317 Roo.apply(Roo.bootstrap.TimeField, {
20347 cls: 'btn btn-info ok',
20359 Roo.apply(Roo.bootstrap.TimeField, {
20363 cls: 'datepicker dropdown-menu',
20367 cls: 'datepicker-time',
20371 cls: 'table-condensed',
20373 Roo.bootstrap.TimeField.content,
20374 Roo.bootstrap.TimeField.footer
20393 * @class Roo.bootstrap.MonthField
20394 * @extends Roo.bootstrap.Input
20395 * Bootstrap MonthField class
20397 * @cfg {String} language default en
20400 * Create a new MonthField
20401 * @param {Object} config The config object
20404 Roo.bootstrap.MonthField = function(config){
20405 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20410 * Fires when this field show.
20411 * @param {Roo.bootstrap.MonthField} this
20412 * @param {Mixed} date The date value
20417 * Fires when this field hide.
20418 * @param {Roo.bootstrap.MonthField} this
20419 * @param {Mixed} date The date value
20424 * Fires when select a date.
20425 * @param {Roo.bootstrap.MonthField} this
20426 * @param {String} oldvalue The old value
20427 * @param {String} newvalue The new value
20433 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20435 onRender: function(ct, position)
20438 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20440 this.language = this.language || 'en';
20441 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20442 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20444 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20445 this.isInline = false;
20446 this.isInput = true;
20447 this.component = this.el.select('.add-on', true).first() || false;
20448 this.component = (this.component && this.component.length === 0) ? false : this.component;
20449 this.hasInput = this.component && this.inputEL().length;
20451 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20453 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20455 this.picker().on('mousedown', this.onMousedown, this);
20456 this.picker().on('click', this.onClick, this);
20458 this.picker().addClass('datepicker-dropdown');
20460 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20461 v.setStyle('width', '189px');
20468 if(this.isInline) {
20474 setValue: function(v, suppressEvent)
20476 var o = this.getValue();
20478 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20482 if(suppressEvent !== true){
20483 this.fireEvent('select', this, o, v);
20488 getValue: function()
20493 onClick: function(e)
20495 e.stopPropagation();
20496 e.preventDefault();
20498 var target = e.getTarget();
20500 if(target.nodeName.toLowerCase() === 'i'){
20501 target = Roo.get(target).dom.parentNode;
20504 var nodeName = target.nodeName;
20505 var className = target.className;
20506 var html = target.innerHTML;
20508 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20512 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20514 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20520 picker : function()
20522 return this.pickerEl;
20525 fillMonths: function()
20528 var months = this.picker().select('>.datepicker-months td', true).first();
20530 months.dom.innerHTML = '';
20536 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20539 months.createChild(month);
20548 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20549 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20552 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20553 e.removeClass('active');
20555 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20556 e.addClass('active');
20563 if(this.isInline) {
20567 this.picker().removeClass(['bottom', 'top']);
20569 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20571 * place to the top of element!
20575 this.picker().addClass('top');
20576 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20581 this.picker().addClass('bottom');
20583 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20586 onFocus : function()
20588 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20592 onBlur : function()
20594 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20596 var d = this.inputEl().getValue();
20605 this.picker().show();
20606 this.picker().select('>.datepicker-months', true).first().show();
20610 this.fireEvent('show', this, this.date);
20615 if(this.isInline) {
20618 this.picker().hide();
20619 this.fireEvent('hide', this, this.date);
20623 onMousedown: function(e)
20625 e.stopPropagation();
20626 e.preventDefault();
20631 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20635 fireKey: function(e)
20637 if (!this.picker().isVisible()){
20638 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20649 e.preventDefault();
20653 dir = e.keyCode == 37 ? -1 : 1;
20655 this.vIndex = this.vIndex + dir;
20657 if(this.vIndex < 0){
20661 if(this.vIndex > 11){
20665 if(isNaN(this.vIndex)){
20669 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20675 dir = e.keyCode == 38 ? -1 : 1;
20677 this.vIndex = this.vIndex + dir * 4;
20679 if(this.vIndex < 0){
20683 if(this.vIndex > 11){
20687 if(isNaN(this.vIndex)){
20691 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20696 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20697 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20701 e.preventDefault();
20704 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20705 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20721 this.picker().remove();
20726 Roo.apply(Roo.bootstrap.MonthField, {
20745 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20746 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20751 Roo.apply(Roo.bootstrap.MonthField, {
20755 cls: 'datepicker dropdown-menu roo-dynamic',
20759 cls: 'datepicker-months',
20763 cls: 'table-condensed',
20765 Roo.bootstrap.DateField.content
20785 * @class Roo.bootstrap.CheckBox
20786 * @extends Roo.bootstrap.Input
20787 * Bootstrap CheckBox class
20789 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20790 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20791 * @cfg {String} boxLabel The text that appears beside the checkbox
20792 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20793 * @cfg {Boolean} checked initnal the element
20794 * @cfg {Boolean} inline inline the element (default false)
20795 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20796 * @cfg {String} tooltip label tooltip
20799 * Create a new CheckBox
20800 * @param {Object} config The config object
20803 Roo.bootstrap.CheckBox = function(config){
20804 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20809 * Fires when the element is checked or unchecked.
20810 * @param {Roo.bootstrap.CheckBox} this This input
20811 * @param {Boolean} checked The new checked value
20816 * Fires when the element is click.
20817 * @param {Roo.bootstrap.CheckBox} this This input
20824 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20826 inputType: 'checkbox',
20835 getAutoCreate : function()
20837 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20843 cfg.cls = 'form-group ' + this.inputType; //input-group
20846 cfg.cls += ' ' + this.inputType + '-inline';
20852 type : this.inputType,
20853 value : this.inputValue,
20854 cls : 'roo-' + this.inputType, //'form-box',
20855 placeholder : this.placeholder || ''
20859 if(this.inputType != 'radio'){
20863 cls : 'roo-hidden-value',
20864 value : this.checked ? this.inputValue : this.valueOff
20869 if (this.weight) { // Validity check?
20870 cfg.cls += " " + this.inputType + "-" + this.weight;
20873 if (this.disabled) {
20874 input.disabled=true;
20878 input.checked = this.checked;
20883 input.name = this.name;
20885 if(this.inputType != 'radio'){
20886 hidden.name = this.name;
20887 input.name = '_hidden_' + this.name;
20892 input.cls += ' input-' + this.size;
20897 ['xs','sm','md','lg'].map(function(size){
20898 if (settings[size]) {
20899 cfg.cls += ' col-' + size + '-' + settings[size];
20903 var inputblock = input;
20905 if (this.before || this.after) {
20908 cls : 'input-group',
20913 inputblock.cn.push({
20915 cls : 'input-group-addon',
20920 inputblock.cn.push(input);
20922 if(this.inputType != 'radio'){
20923 inputblock.cn.push(hidden);
20927 inputblock.cn.push({
20929 cls : 'input-group-addon',
20936 if (align ==='left' && this.fieldLabel.length) {
20937 // Roo.log("left and has label");
20942 cls : 'control-label',
20943 html : this.fieldLabel
20953 if(this.labelWidth > 12){
20954 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20957 if(this.labelWidth < 13 && this.labelmd == 0){
20958 this.labelmd = this.labelWidth;
20961 if(this.labellg > 0){
20962 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20963 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20966 if(this.labelmd > 0){
20967 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20968 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20971 if(this.labelsm > 0){
20972 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20973 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20976 if(this.labelxs > 0){
20977 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20978 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20981 } else if ( this.fieldLabel.length) {
20982 // Roo.log(" label");
20986 tag: this.boxLabel ? 'span' : 'label',
20988 cls: 'control-label box-input-label',
20989 //cls : 'input-group-addon',
20990 html : this.fieldLabel
20999 // Roo.log(" no label && no align");
21000 cfg.cn = [ inputblock ] ;
21006 var boxLabelCfg = {
21008 //'for': id, // box label is handled by onclick - so no for...
21010 html: this.boxLabel
21014 boxLabelCfg.tooltip = this.tooltip;
21017 cfg.cn.push(boxLabelCfg);
21020 if(this.inputType != 'radio'){
21021 cfg.cn.push(hidden);
21029 * return the real input element.
21031 inputEl: function ()
21033 return this.el.select('input.roo-' + this.inputType,true).first();
21035 hiddenEl: function ()
21037 return this.el.select('input.roo-hidden-value',true).first();
21040 labelEl: function()
21042 return this.el.select('label.control-label',true).first();
21044 /* depricated... */
21048 return this.labelEl();
21051 boxLabelEl: function()
21053 return this.el.select('label.box-label',true).first();
21056 initEvents : function()
21058 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21060 this.inputEl().on('click', this.onClick, this);
21062 if (this.boxLabel) {
21063 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21066 this.startValue = this.getValue();
21069 Roo.bootstrap.CheckBox.register(this);
21073 onClick : function(e)
21075 if(this.fireEvent('click', this, e) !== false){
21076 this.setChecked(!this.checked);
21081 setChecked : function(state,suppressEvent)
21083 this.startValue = this.getValue();
21085 if(this.inputType == 'radio'){
21087 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21088 e.dom.checked = false;
21091 this.inputEl().dom.checked = true;
21093 this.inputEl().dom.value = this.inputValue;
21095 if(suppressEvent !== true){
21096 this.fireEvent('check', this, true);
21104 this.checked = state;
21106 this.inputEl().dom.checked = state;
21109 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21111 if(suppressEvent !== true){
21112 this.fireEvent('check', this, state);
21118 getValue : function()
21120 if(this.inputType == 'radio'){
21121 return this.getGroupValue();
21124 return this.hiddenEl().dom.value;
21128 getGroupValue : function()
21130 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21134 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21137 setValue : function(v,suppressEvent)
21139 if(this.inputType == 'radio'){
21140 this.setGroupValue(v, suppressEvent);
21144 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21149 setGroupValue : function(v, suppressEvent)
21151 this.startValue = this.getValue();
21153 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21154 e.dom.checked = false;
21156 if(e.dom.value == v){
21157 e.dom.checked = true;
21161 if(suppressEvent !== true){
21162 this.fireEvent('check', this, true);
21170 validate : function()
21172 if(this.getVisibilityEl().hasClass('hidden')){
21178 (this.inputType == 'radio' && this.validateRadio()) ||
21179 (this.inputType == 'checkbox' && this.validateCheckbox())
21185 this.markInvalid();
21189 validateRadio : function()
21191 if(this.getVisibilityEl().hasClass('hidden')){
21195 if(this.allowBlank){
21201 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21202 if(!e.dom.checked){
21214 validateCheckbox : function()
21217 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21218 //return (this.getValue() == this.inputValue) ? true : false;
21221 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21229 for(var i in group){
21230 if(group[i].el.isVisible(true)){
21238 for(var i in group){
21243 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21250 * Mark this field as valid
21252 markValid : function()
21256 this.fireEvent('valid', this);
21258 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21261 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21268 if(this.inputType == 'radio'){
21269 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21270 var fg = e.findParent('.form-group', false, true);
21271 if (Roo.bootstrap.version == 3) {
21272 fg.removeClass([_this.invalidClass, _this.validClass]);
21273 fg.addClass(_this.validClass);
21275 fg.removeClass(['is-valid', 'is-invalid']);
21276 fg.addClass('is-valid');
21284 var fg = this.el.findParent('.form-group', false, true);
21285 if (Roo.bootstrap.version == 3) {
21286 fg.removeClass([this.invalidClass, this.validClass]);
21287 fg.addClass(this.validClass);
21289 fg.removeClass(['is-valid', 'is-invalid']);
21290 fg.addClass('is-valid');
21295 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21301 for(var i in group){
21302 var fg = group[i].el.findParent('.form-group', false, true);
21303 if (Roo.bootstrap.version == 3) {
21304 fg.removeClass([this.invalidClass, this.validClass]);
21305 fg.addClass(this.validClass);
21307 fg.removeClass(['is-valid', 'is-invalid']);
21308 fg.addClass('is-valid');
21314 * Mark this field as invalid
21315 * @param {String} msg The validation message
21317 markInvalid : function(msg)
21319 if(this.allowBlank){
21325 this.fireEvent('invalid', this, msg);
21327 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21330 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21334 label.markInvalid();
21337 if(this.inputType == 'radio'){
21339 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21340 var fg = e.findParent('.form-group', false, true);
21341 if (Roo.bootstrap.version == 3) {
21342 fg.removeClass([_this.invalidClass, _this.validClass]);
21343 fg.addClass(_this.invalidClass);
21345 fg.removeClass(['is-invalid', 'is-valid']);
21346 fg.addClass('is-invalid');
21354 var fg = this.el.findParent('.form-group', false, true);
21355 if (Roo.bootstrap.version == 3) {
21356 fg.removeClass([_this.invalidClass, _this.validClass]);
21357 fg.addClass(_this.invalidClass);
21359 fg.removeClass(['is-invalid', 'is-valid']);
21360 fg.addClass('is-invalid');
21365 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21371 for(var i in group){
21372 var fg = group[i].el.findParent('.form-group', false, true);
21373 if (Roo.bootstrap.version == 3) {
21374 fg.removeClass([_this.invalidClass, _this.validClass]);
21375 fg.addClass(_this.invalidClass);
21377 fg.removeClass(['is-invalid', 'is-valid']);
21378 fg.addClass('is-invalid');
21384 clearInvalid : function()
21386 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21388 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21390 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21392 if (label && label.iconEl) {
21393 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21394 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21398 disable : function()
21400 if(this.inputType != 'radio'){
21401 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21408 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21409 _this.getActionEl().addClass(this.disabledClass);
21410 e.dom.disabled = true;
21414 this.disabled = true;
21415 this.fireEvent("disable", this);
21419 enable : function()
21421 if(this.inputType != 'radio'){
21422 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21429 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21430 _this.getActionEl().removeClass(this.disabledClass);
21431 e.dom.disabled = false;
21435 this.disabled = false;
21436 this.fireEvent("enable", this);
21440 setBoxLabel : function(v)
21445 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21451 Roo.apply(Roo.bootstrap.CheckBox, {
21456 * register a CheckBox Group
21457 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21459 register : function(checkbox)
21461 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21462 this.groups[checkbox.groupId] = {};
21465 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21469 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21473 * fetch a CheckBox Group based on the group ID
21474 * @param {string} the group ID
21475 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21477 get: function(groupId) {
21478 if (typeof(this.groups[groupId]) == 'undefined') {
21482 return this.groups[groupId] ;
21495 * @class Roo.bootstrap.Radio
21496 * @extends Roo.bootstrap.Component
21497 * Bootstrap Radio class
21498 * @cfg {String} boxLabel - the label associated
21499 * @cfg {String} value - the value of radio
21502 * Create a new Radio
21503 * @param {Object} config The config object
21505 Roo.bootstrap.Radio = function(config){
21506 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21510 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21516 getAutoCreate : function()
21520 cls : 'form-group radio',
21525 html : this.boxLabel
21533 initEvents : function()
21535 this.parent().register(this);
21537 this.el.on('click', this.onClick, this);
21541 onClick : function(e)
21543 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21544 this.setChecked(true);
21548 setChecked : function(state, suppressEvent)
21550 this.parent().setValue(this.value, suppressEvent);
21554 setBoxLabel : function(v)
21559 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21574 * @class Roo.bootstrap.SecurePass
21575 * @extends Roo.bootstrap.Input
21576 * Bootstrap SecurePass class
21580 * Create a new SecurePass
21581 * @param {Object} config The config object
21584 Roo.bootstrap.SecurePass = function (config) {
21585 // these go here, so the translation tool can replace them..
21587 PwdEmpty: "Please type a password, and then retype it to confirm.",
21588 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21589 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21590 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21591 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21592 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21593 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21594 TooWeak: "Your password is Too Weak."
21596 this.meterLabel = "Password strength:";
21597 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21598 this.meterClass = [
21599 "roo-password-meter-tooweak",
21600 "roo-password-meter-weak",
21601 "roo-password-meter-medium",
21602 "roo-password-meter-strong",
21603 "roo-password-meter-grey"
21608 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21611 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21613 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21615 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21616 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21617 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21618 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21619 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21620 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21621 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21631 * @cfg {String/Object} Label for the strength meter (defaults to
21632 * 'Password strength:')
21637 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21638 * ['Weak', 'Medium', 'Strong'])
21641 pwdStrengths: false,
21654 initEvents: function ()
21656 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21658 if (this.el.is('input[type=password]') && Roo.isSafari) {
21659 this.el.on('keydown', this.SafariOnKeyDown, this);
21662 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21665 onRender: function (ct, position)
21667 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21668 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21669 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21671 this.trigger.createChild({
21676 cls: 'roo-password-meter-grey col-xs-12',
21679 //width: this.meterWidth + 'px'
21683 cls: 'roo-password-meter-text'
21689 if (this.hideTrigger) {
21690 this.trigger.setDisplayed(false);
21692 this.setSize(this.width || '', this.height || '');
21695 onDestroy: function ()
21697 if (this.trigger) {
21698 this.trigger.removeAllListeners();
21699 this.trigger.remove();
21702 this.wrap.remove();
21704 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21707 checkStrength: function ()
21709 var pwd = this.inputEl().getValue();
21710 if (pwd == this._lastPwd) {
21715 if (this.ClientSideStrongPassword(pwd)) {
21717 } else if (this.ClientSideMediumPassword(pwd)) {
21719 } else if (this.ClientSideWeakPassword(pwd)) {
21725 Roo.log('strength1: ' + strength);
21727 //var pm = this.trigger.child('div/div/div').dom;
21728 var pm = this.trigger.child('div/div');
21729 pm.removeClass(this.meterClass);
21730 pm.addClass(this.meterClass[strength]);
21733 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21735 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21737 this._lastPwd = pwd;
21741 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21743 this._lastPwd = '';
21745 var pm = this.trigger.child('div/div');
21746 pm.removeClass(this.meterClass);
21747 pm.addClass('roo-password-meter-grey');
21750 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21753 this.inputEl().dom.type='password';
21756 validateValue: function (value)
21759 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21762 if (value.length == 0) {
21763 if (this.allowBlank) {
21764 this.clearInvalid();
21768 this.markInvalid(this.errors.PwdEmpty);
21769 this.errorMsg = this.errors.PwdEmpty;
21777 if ('[\x21-\x7e]*'.match(value)) {
21778 this.markInvalid(this.errors.PwdBadChar);
21779 this.errorMsg = this.errors.PwdBadChar;
21782 if (value.length < 6) {
21783 this.markInvalid(this.errors.PwdShort);
21784 this.errorMsg = this.errors.PwdShort;
21787 if (value.length > 16) {
21788 this.markInvalid(this.errors.PwdLong);
21789 this.errorMsg = this.errors.PwdLong;
21793 if (this.ClientSideStrongPassword(value)) {
21795 } else if (this.ClientSideMediumPassword(value)) {
21797 } else if (this.ClientSideWeakPassword(value)) {
21804 if (strength < 2) {
21805 //this.markInvalid(this.errors.TooWeak);
21806 this.errorMsg = this.errors.TooWeak;
21811 console.log('strength2: ' + strength);
21813 //var pm = this.trigger.child('div/div/div').dom;
21815 var pm = this.trigger.child('div/div');
21816 pm.removeClass(this.meterClass);
21817 pm.addClass(this.meterClass[strength]);
21819 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21821 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21823 this.errorMsg = '';
21827 CharacterSetChecks: function (type)
21830 this.fResult = false;
21833 isctype: function (character, type)
21836 case this.kCapitalLetter:
21837 if (character >= 'A' && character <= 'Z') {
21842 case this.kSmallLetter:
21843 if (character >= 'a' && character <= 'z') {
21849 if (character >= '0' && character <= '9') {
21854 case this.kPunctuation:
21855 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21866 IsLongEnough: function (pwd, size)
21868 return !(pwd == null || isNaN(size) || pwd.length < size);
21871 SpansEnoughCharacterSets: function (word, nb)
21873 if (!this.IsLongEnough(word, nb))
21878 var characterSetChecks = new Array(
21879 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21880 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21883 for (var index = 0; index < word.length; ++index) {
21884 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21885 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21886 characterSetChecks[nCharSet].fResult = true;
21893 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21894 if (characterSetChecks[nCharSet].fResult) {
21899 if (nCharSets < nb) {
21905 ClientSideStrongPassword: function (pwd)
21907 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21910 ClientSideMediumPassword: function (pwd)
21912 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21915 ClientSideWeakPassword: function (pwd)
21917 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21920 })//<script type="text/javascript">
21923 * Based Ext JS Library 1.1.1
21924 * Copyright(c) 2006-2007, Ext JS, LLC.
21930 * @class Roo.HtmlEditorCore
21931 * @extends Roo.Component
21932 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21934 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21937 Roo.HtmlEditorCore = function(config){
21940 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21945 * @event initialize
21946 * Fires when the editor is fully initialized (including the iframe)
21947 * @param {Roo.HtmlEditorCore} this
21952 * Fires when the editor is first receives the focus. Any insertion must wait
21953 * until after this event.
21954 * @param {Roo.HtmlEditorCore} this
21958 * @event beforesync
21959 * Fires before the textarea is updated with content from the editor iframe. Return false
21960 * to cancel the sync.
21961 * @param {Roo.HtmlEditorCore} this
21962 * @param {String} html
21966 * @event beforepush
21967 * Fires before the iframe editor is updated with content from the textarea. Return false
21968 * to cancel the push.
21969 * @param {Roo.HtmlEditorCore} this
21970 * @param {String} html
21975 * Fires when the textarea is updated with content from the editor iframe.
21976 * @param {Roo.HtmlEditorCore} this
21977 * @param {String} html
21982 * Fires when the iframe editor is updated with content from the textarea.
21983 * @param {Roo.HtmlEditorCore} this
21984 * @param {String} html
21989 * @event editorevent
21990 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21991 * @param {Roo.HtmlEditorCore} this
21997 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21999 // defaults : white / black...
22000 this.applyBlacklists();
22007 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22011 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22017 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22022 * @cfg {Number} height (in pixels)
22026 * @cfg {Number} width (in pixels)
22031 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22034 stylesheets: false,
22039 // private properties
22040 validationEvent : false,
22042 initialized : false,
22044 sourceEditMode : false,
22045 onFocus : Roo.emptyFn,
22047 hideMode:'offsets',
22051 // blacklist + whitelisted elements..
22058 * Protected method that will not generally be called directly. It
22059 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22060 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22062 getDocMarkup : function(){
22066 // inherit styels from page...??
22067 if (this.stylesheets === false) {
22069 Roo.get(document.head).select('style').each(function(node) {
22070 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22073 Roo.get(document.head).select('link').each(function(node) {
22074 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22077 } else if (!this.stylesheets.length) {
22079 st = '<style type="text/css">' +
22080 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22083 st = '<style type="text/css">' +
22088 st += '<style type="text/css">' +
22089 'IMG { cursor: pointer } ' +
22092 var cls = 'roo-htmleditor-body';
22094 if(this.bodyCls.length){
22095 cls += ' ' + this.bodyCls;
22098 return '<html><head>' + st +
22099 //<style type="text/css">' +
22100 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22102 ' </head><body class="' + cls + '"></body></html>';
22106 onRender : function(ct, position)
22109 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22110 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22113 this.el.dom.style.border = '0 none';
22114 this.el.dom.setAttribute('tabIndex', -1);
22115 this.el.addClass('x-hidden hide');
22119 if(Roo.isIE){ // fix IE 1px bogus margin
22120 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22124 this.frameId = Roo.id();
22128 var iframe = this.owner.wrap.createChild({
22130 cls: 'form-control', // bootstrap..
22132 name: this.frameId,
22133 frameBorder : 'no',
22134 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22139 this.iframe = iframe.dom;
22141 this.assignDocWin();
22143 this.doc.designMode = 'on';
22146 this.doc.write(this.getDocMarkup());
22150 var task = { // must defer to wait for browser to be ready
22152 //console.log("run task?" + this.doc.readyState);
22153 this.assignDocWin();
22154 if(this.doc.body || this.doc.readyState == 'complete'){
22156 this.doc.designMode="on";
22160 Roo.TaskMgr.stop(task);
22161 this.initEditor.defer(10, this);
22168 Roo.TaskMgr.start(task);
22173 onResize : function(w, h)
22175 Roo.log('resize: ' +w + ',' + h );
22176 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22180 if(typeof w == 'number'){
22182 this.iframe.style.width = w + 'px';
22184 if(typeof h == 'number'){
22186 this.iframe.style.height = h + 'px';
22188 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22195 * Toggles the editor between standard and source edit mode.
22196 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22198 toggleSourceEdit : function(sourceEditMode){
22200 this.sourceEditMode = sourceEditMode === true;
22202 if(this.sourceEditMode){
22204 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22207 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22208 //this.iframe.className = '';
22211 //this.setSize(this.owner.wrap.getSize());
22212 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22219 * Protected method that will not generally be called directly. If you need/want
22220 * custom HTML cleanup, this is the method you should override.
22221 * @param {String} html The HTML to be cleaned
22222 * return {String} The cleaned HTML
22224 cleanHtml : function(html){
22225 html = String(html);
22226 if(html.length > 5){
22227 if(Roo.isSafari){ // strip safari nonsense
22228 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22231 if(html == ' '){
22238 * HTML Editor -> Textarea
22239 * Protected method that will not generally be called directly. Syncs the contents
22240 * of the editor iframe with the textarea.
22242 syncValue : function(){
22243 if(this.initialized){
22244 var bd = (this.doc.body || this.doc.documentElement);
22245 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22246 var html = bd.innerHTML;
22248 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22249 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22251 html = '<div style="'+m[0]+'">' + html + '</div>';
22254 html = this.cleanHtml(html);
22255 // fix up the special chars.. normaly like back quotes in word...
22256 // however we do not want to do this with chinese..
22257 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22258 var cc = b.charCodeAt();
22260 (cc >= 0x4E00 && cc < 0xA000 ) ||
22261 (cc >= 0x3400 && cc < 0x4E00 ) ||
22262 (cc >= 0xf900 && cc < 0xfb00 )
22268 if(this.owner.fireEvent('beforesync', this, html) !== false){
22269 this.el.dom.value = html;
22270 this.owner.fireEvent('sync', this, html);
22276 * Protected method that will not generally be called directly. Pushes the value of the textarea
22277 * into the iframe editor.
22279 pushValue : function(){
22280 if(this.initialized){
22281 var v = this.el.dom.value.trim();
22283 // if(v.length < 1){
22287 if(this.owner.fireEvent('beforepush', this, v) !== false){
22288 var d = (this.doc.body || this.doc.documentElement);
22290 this.cleanUpPaste();
22291 this.el.dom.value = d.innerHTML;
22292 this.owner.fireEvent('push', this, v);
22298 deferFocus : function(){
22299 this.focus.defer(10, this);
22303 focus : function(){
22304 if(this.win && !this.sourceEditMode){
22311 assignDocWin: function()
22313 var iframe = this.iframe;
22316 this.doc = iframe.contentWindow.document;
22317 this.win = iframe.contentWindow;
22319 // if (!Roo.get(this.frameId)) {
22322 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22323 // this.win = Roo.get(this.frameId).dom.contentWindow;
22325 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22329 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22330 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22335 initEditor : function(){
22336 //console.log("INIT EDITOR");
22337 this.assignDocWin();
22341 this.doc.designMode="on";
22343 this.doc.write(this.getDocMarkup());
22346 var dbody = (this.doc.body || this.doc.documentElement);
22347 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22348 // this copies styles from the containing element into thsi one..
22349 // not sure why we need all of this..
22350 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22352 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22353 //ss['background-attachment'] = 'fixed'; // w3c
22354 dbody.bgProperties = 'fixed'; // ie
22355 //Roo.DomHelper.applyStyles(dbody, ss);
22356 Roo.EventManager.on(this.doc, {
22357 //'mousedown': this.onEditorEvent,
22358 'mouseup': this.onEditorEvent,
22359 'dblclick': this.onEditorEvent,
22360 'click': this.onEditorEvent,
22361 'keyup': this.onEditorEvent,
22366 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22368 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22369 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22371 this.initialized = true;
22373 this.owner.fireEvent('initialize', this);
22378 onDestroy : function(){
22384 //for (var i =0; i < this.toolbars.length;i++) {
22385 // // fixme - ask toolbars for heights?
22386 // this.toolbars[i].onDestroy();
22389 //this.wrap.dom.innerHTML = '';
22390 //this.wrap.remove();
22395 onFirstFocus : function(){
22397 this.assignDocWin();
22400 this.activated = true;
22403 if(Roo.isGecko){ // prevent silly gecko errors
22405 var s = this.win.getSelection();
22406 if(!s.focusNode || s.focusNode.nodeType != 3){
22407 var r = s.getRangeAt(0);
22408 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22413 this.execCmd('useCSS', true);
22414 this.execCmd('styleWithCSS', false);
22417 this.owner.fireEvent('activate', this);
22421 adjustFont: function(btn){
22422 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22423 //if(Roo.isSafari){ // safari
22426 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22427 if(Roo.isSafari){ // safari
22428 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22429 v = (v < 10) ? 10 : v;
22430 v = (v > 48) ? 48 : v;
22431 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22436 v = Math.max(1, v+adjust);
22438 this.execCmd('FontSize', v );
22441 onEditorEvent : function(e)
22443 this.owner.fireEvent('editorevent', this, e);
22444 // this.updateToolbar();
22445 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22448 insertTag : function(tg)
22450 // could be a bit smarter... -> wrap the current selected tRoo..
22451 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22453 range = this.createRange(this.getSelection());
22454 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22455 wrappingNode.appendChild(range.extractContents());
22456 range.insertNode(wrappingNode);
22463 this.execCmd("formatblock", tg);
22467 insertText : function(txt)
22471 var range = this.createRange();
22472 range.deleteContents();
22473 //alert(Sender.getAttribute('label'));
22475 range.insertNode(this.doc.createTextNode(txt));
22481 * Executes a Midas editor command on the editor document and performs necessary focus and
22482 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22483 * @param {String} cmd The Midas command
22484 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22486 relayCmd : function(cmd, value){
22488 this.execCmd(cmd, value);
22489 this.owner.fireEvent('editorevent', this);
22490 //this.updateToolbar();
22491 this.owner.deferFocus();
22495 * Executes a Midas editor command directly on the editor document.
22496 * For visual commands, you should use {@link #relayCmd} instead.
22497 * <b>This should only be called after the editor is initialized.</b>
22498 * @param {String} cmd The Midas command
22499 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22501 execCmd : function(cmd, value){
22502 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22509 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22511 * @param {String} text | dom node..
22513 insertAtCursor : function(text)
22516 if(!this.activated){
22522 var r = this.doc.selection.createRange();
22533 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22537 // from jquery ui (MIT licenced)
22539 var win = this.win;
22541 if (win.getSelection && win.getSelection().getRangeAt) {
22542 range = win.getSelection().getRangeAt(0);
22543 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22544 range.insertNode(node);
22545 } else if (win.document.selection && win.document.selection.createRange) {
22546 // no firefox support
22547 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22548 win.document.selection.createRange().pasteHTML(txt);
22550 // no firefox support
22551 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22552 this.execCmd('InsertHTML', txt);
22561 mozKeyPress : function(e){
22563 var c = e.getCharCode(), cmd;
22566 c = String.fromCharCode(c).toLowerCase();
22580 this.cleanUpPaste.defer(100, this);
22588 e.preventDefault();
22596 fixKeys : function(){ // load time branching for fastest keydown performance
22598 return function(e){
22599 var k = e.getKey(), r;
22602 r = this.doc.selection.createRange();
22605 r.pasteHTML('    ');
22612 r = this.doc.selection.createRange();
22614 var target = r.parentElement();
22615 if(!target || target.tagName.toLowerCase() != 'li'){
22617 r.pasteHTML('<br />');
22623 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22624 this.cleanUpPaste.defer(100, this);
22630 }else if(Roo.isOpera){
22631 return function(e){
22632 var k = e.getKey();
22636 this.execCmd('InsertHTML','    ');
22639 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22640 this.cleanUpPaste.defer(100, this);
22645 }else if(Roo.isSafari){
22646 return function(e){
22647 var k = e.getKey();
22651 this.execCmd('InsertText','\t');
22655 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22656 this.cleanUpPaste.defer(100, this);
22664 getAllAncestors: function()
22666 var p = this.getSelectedNode();
22669 a.push(p); // push blank onto stack..
22670 p = this.getParentElement();
22674 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22678 a.push(this.doc.body);
22682 lastSelNode : false,
22685 getSelection : function()
22687 this.assignDocWin();
22688 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22691 getSelectedNode: function()
22693 // this may only work on Gecko!!!
22695 // should we cache this!!!!
22700 var range = this.createRange(this.getSelection()).cloneRange();
22703 var parent = range.parentElement();
22705 var testRange = range.duplicate();
22706 testRange.moveToElementText(parent);
22707 if (testRange.inRange(range)) {
22710 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22713 parent = parent.parentElement;
22718 // is ancestor a text element.
22719 var ac = range.commonAncestorContainer;
22720 if (ac.nodeType == 3) {
22721 ac = ac.parentNode;
22724 var ar = ac.childNodes;
22727 var other_nodes = [];
22728 var has_other_nodes = false;
22729 for (var i=0;i<ar.length;i++) {
22730 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22733 // fullly contained node.
22735 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22740 // probably selected..
22741 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22742 other_nodes.push(ar[i]);
22746 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22751 has_other_nodes = true;
22753 if (!nodes.length && other_nodes.length) {
22754 nodes= other_nodes;
22756 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22762 createRange: function(sel)
22764 // this has strange effects when using with
22765 // top toolbar - not sure if it's a great idea.
22766 //this.editor.contentWindow.focus();
22767 if (typeof sel != "undefined") {
22769 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22771 return this.doc.createRange();
22774 return this.doc.createRange();
22777 getParentElement: function()
22780 this.assignDocWin();
22781 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22783 var range = this.createRange(sel);
22786 var p = range.commonAncestorContainer;
22787 while (p.nodeType == 3) { // text node
22798 * Range intersection.. the hard stuff...
22802 * [ -- selected range --- ]
22806 * if end is before start or hits it. fail.
22807 * if start is after end or hits it fail.
22809 * if either hits (but other is outside. - then it's not
22815 // @see http://www.thismuchiknow.co.uk/?p=64.
22816 rangeIntersectsNode : function(range, node)
22818 var nodeRange = node.ownerDocument.createRange();
22820 nodeRange.selectNode(node);
22822 nodeRange.selectNodeContents(node);
22825 var rangeStartRange = range.cloneRange();
22826 rangeStartRange.collapse(true);
22828 var rangeEndRange = range.cloneRange();
22829 rangeEndRange.collapse(false);
22831 var nodeStartRange = nodeRange.cloneRange();
22832 nodeStartRange.collapse(true);
22834 var nodeEndRange = nodeRange.cloneRange();
22835 nodeEndRange.collapse(false);
22837 return rangeStartRange.compareBoundaryPoints(
22838 Range.START_TO_START, nodeEndRange) == -1 &&
22839 rangeEndRange.compareBoundaryPoints(
22840 Range.START_TO_START, nodeStartRange) == 1;
22844 rangeCompareNode : function(range, node)
22846 var nodeRange = node.ownerDocument.createRange();
22848 nodeRange.selectNode(node);
22850 nodeRange.selectNodeContents(node);
22854 range.collapse(true);
22856 nodeRange.collapse(true);
22858 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22859 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22861 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22863 var nodeIsBefore = ss == 1;
22864 var nodeIsAfter = ee == -1;
22866 if (nodeIsBefore && nodeIsAfter) {
22869 if (!nodeIsBefore && nodeIsAfter) {
22870 return 1; //right trailed.
22873 if (nodeIsBefore && !nodeIsAfter) {
22874 return 2; // left trailed.
22880 // private? - in a new class?
22881 cleanUpPaste : function()
22883 // cleans up the whole document..
22884 Roo.log('cleanuppaste');
22886 this.cleanUpChildren(this.doc.body);
22887 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22888 if (clean != this.doc.body.innerHTML) {
22889 this.doc.body.innerHTML = clean;
22894 cleanWordChars : function(input) {// change the chars to hex code
22895 var he = Roo.HtmlEditorCore;
22897 var output = input;
22898 Roo.each(he.swapCodes, function(sw) {
22899 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22901 output = output.replace(swapper, sw[1]);
22908 cleanUpChildren : function (n)
22910 if (!n.childNodes.length) {
22913 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22914 this.cleanUpChild(n.childNodes[i]);
22921 cleanUpChild : function (node)
22924 //console.log(node);
22925 if (node.nodeName == "#text") {
22926 // clean up silly Windows -- stuff?
22929 if (node.nodeName == "#comment") {
22930 node.parentNode.removeChild(node);
22931 // clean up silly Windows -- stuff?
22934 var lcname = node.tagName.toLowerCase();
22935 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22936 // whitelist of tags..
22938 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22940 node.parentNode.removeChild(node);
22945 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22947 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22948 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22950 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22951 // remove_keep_children = true;
22954 if (remove_keep_children) {
22955 this.cleanUpChildren(node);
22956 // inserts everything just before this node...
22957 while (node.childNodes.length) {
22958 var cn = node.childNodes[0];
22959 node.removeChild(cn);
22960 node.parentNode.insertBefore(cn, node);
22962 node.parentNode.removeChild(node);
22966 if (!node.attributes || !node.attributes.length) {
22967 this.cleanUpChildren(node);
22971 function cleanAttr(n,v)
22974 if (v.match(/^\./) || v.match(/^\//)) {
22977 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22980 if (v.match(/^#/)) {
22983 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22984 node.removeAttribute(n);
22988 var cwhite = this.cwhite;
22989 var cblack = this.cblack;
22991 function cleanStyle(n,v)
22993 if (v.match(/expression/)) { //XSS?? should we even bother..
22994 node.removeAttribute(n);
22998 var parts = v.split(/;/);
23001 Roo.each(parts, function(p) {
23002 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23006 var l = p.split(':').shift().replace(/\s+/g,'');
23007 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23009 if ( cwhite.length && cblack.indexOf(l) > -1) {
23010 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23011 //node.removeAttribute(n);
23015 // only allow 'c whitelisted system attributes'
23016 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23017 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23018 //node.removeAttribute(n);
23028 if (clean.length) {
23029 node.setAttribute(n, clean.join(';'));
23031 node.removeAttribute(n);
23037 for (var i = node.attributes.length-1; i > -1 ; i--) {
23038 var a = node.attributes[i];
23041 if (a.name.toLowerCase().substr(0,2)=='on') {
23042 node.removeAttribute(a.name);
23045 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23046 node.removeAttribute(a.name);
23049 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23050 cleanAttr(a.name,a.value); // fixme..
23053 if (a.name == 'style') {
23054 cleanStyle(a.name,a.value);
23057 /// clean up MS crap..
23058 // tecnically this should be a list of valid class'es..
23061 if (a.name == 'class') {
23062 if (a.value.match(/^Mso/)) {
23063 node.className = '';
23066 if (a.value.match(/^body$/)) {
23067 node.className = '';
23078 this.cleanUpChildren(node);
23084 * Clean up MS wordisms...
23086 cleanWord : function(node)
23091 this.cleanWord(this.doc.body);
23094 if (node.nodeName == "#text") {
23095 // clean up silly Windows -- stuff?
23098 if (node.nodeName == "#comment") {
23099 node.parentNode.removeChild(node);
23100 // clean up silly Windows -- stuff?
23104 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23105 node.parentNode.removeChild(node);
23109 // remove - but keep children..
23110 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23111 while (node.childNodes.length) {
23112 var cn = node.childNodes[0];
23113 node.removeChild(cn);
23114 node.parentNode.insertBefore(cn, node);
23116 node.parentNode.removeChild(node);
23117 this.iterateChildren(node, this.cleanWord);
23121 if (node.className.length) {
23123 var cn = node.className.split(/\W+/);
23125 Roo.each(cn, function(cls) {
23126 if (cls.match(/Mso[a-zA-Z]+/)) {
23131 node.className = cna.length ? cna.join(' ') : '';
23133 node.removeAttribute("class");
23137 if (node.hasAttribute("lang")) {
23138 node.removeAttribute("lang");
23141 if (node.hasAttribute("style")) {
23143 var styles = node.getAttribute("style").split(";");
23145 Roo.each(styles, function(s) {
23146 if (!s.match(/:/)) {
23149 var kv = s.split(":");
23150 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23153 // what ever is left... we allow.
23156 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23157 if (!nstyle.length) {
23158 node.removeAttribute('style');
23161 this.iterateChildren(node, this.cleanWord);
23167 * iterateChildren of a Node, calling fn each time, using this as the scole..
23168 * @param {DomNode} node node to iterate children of.
23169 * @param {Function} fn method of this class to call on each item.
23171 iterateChildren : function(node, fn)
23173 if (!node.childNodes.length) {
23176 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23177 fn.call(this, node.childNodes[i])
23183 * cleanTableWidths.
23185 * Quite often pasting from word etc.. results in tables with column and widths.
23186 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23189 cleanTableWidths : function(node)
23194 this.cleanTableWidths(this.doc.body);
23199 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23202 Roo.log(node.tagName);
23203 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23204 this.iterateChildren(node, this.cleanTableWidths);
23207 if (node.hasAttribute('width')) {
23208 node.removeAttribute('width');
23212 if (node.hasAttribute("style")) {
23215 var styles = node.getAttribute("style").split(";");
23217 Roo.each(styles, function(s) {
23218 if (!s.match(/:/)) {
23221 var kv = s.split(":");
23222 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23225 // what ever is left... we allow.
23228 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23229 if (!nstyle.length) {
23230 node.removeAttribute('style');
23234 this.iterateChildren(node, this.cleanTableWidths);
23242 domToHTML : function(currentElement, depth, nopadtext) {
23244 depth = depth || 0;
23245 nopadtext = nopadtext || false;
23247 if (!currentElement) {
23248 return this.domToHTML(this.doc.body);
23251 //Roo.log(currentElement);
23253 var allText = false;
23254 var nodeName = currentElement.nodeName;
23255 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23257 if (nodeName == '#text') {
23259 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23264 if (nodeName != 'BODY') {
23267 // Prints the node tagName, such as <A>, <IMG>, etc
23270 for(i = 0; i < currentElement.attributes.length;i++) {
23272 var aname = currentElement.attributes.item(i).name;
23273 if (!currentElement.attributes.item(i).value.length) {
23276 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23279 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23288 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23291 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23296 // Traverse the tree
23298 var currentElementChild = currentElement.childNodes.item(i);
23299 var allText = true;
23300 var innerHTML = '';
23302 while (currentElementChild) {
23303 // Formatting code (indent the tree so it looks nice on the screen)
23304 var nopad = nopadtext;
23305 if (lastnode == 'SPAN') {
23309 if (currentElementChild.nodeName == '#text') {
23310 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23311 toadd = nopadtext ? toadd : toadd.trim();
23312 if (!nopad && toadd.length > 80) {
23313 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23315 innerHTML += toadd;
23318 currentElementChild = currentElement.childNodes.item(i);
23324 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23326 // Recursively traverse the tree structure of the child node
23327 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23328 lastnode = currentElementChild.nodeName;
23330 currentElementChild=currentElement.childNodes.item(i);
23336 // The remaining code is mostly for formatting the tree
23337 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23342 ret+= "</"+tagName+">";
23348 applyBlacklists : function()
23350 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23351 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23355 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23356 if (b.indexOf(tag) > -1) {
23359 this.white.push(tag);
23363 Roo.each(w, function(tag) {
23364 if (b.indexOf(tag) > -1) {
23367 if (this.white.indexOf(tag) > -1) {
23370 this.white.push(tag);
23375 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23376 if (w.indexOf(tag) > -1) {
23379 this.black.push(tag);
23383 Roo.each(b, function(tag) {
23384 if (w.indexOf(tag) > -1) {
23387 if (this.black.indexOf(tag) > -1) {
23390 this.black.push(tag);
23395 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23396 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23400 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23401 if (b.indexOf(tag) > -1) {
23404 this.cwhite.push(tag);
23408 Roo.each(w, function(tag) {
23409 if (b.indexOf(tag) > -1) {
23412 if (this.cwhite.indexOf(tag) > -1) {
23415 this.cwhite.push(tag);
23420 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23421 if (w.indexOf(tag) > -1) {
23424 this.cblack.push(tag);
23428 Roo.each(b, function(tag) {
23429 if (w.indexOf(tag) > -1) {
23432 if (this.cblack.indexOf(tag) > -1) {
23435 this.cblack.push(tag);
23440 setStylesheets : function(stylesheets)
23442 if(typeof(stylesheets) == 'string'){
23443 Roo.get(this.iframe.contentDocument.head).createChild({
23445 rel : 'stylesheet',
23454 Roo.each(stylesheets, function(s) {
23459 Roo.get(_this.iframe.contentDocument.head).createChild({
23461 rel : 'stylesheet',
23470 removeStylesheets : function()
23474 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23479 setStyle : function(style)
23481 Roo.get(this.iframe.contentDocument.head).createChild({
23490 // hide stuff that is not compatible
23504 * @event specialkey
23508 * @cfg {String} fieldClass @hide
23511 * @cfg {String} focusClass @hide
23514 * @cfg {String} autoCreate @hide
23517 * @cfg {String} inputType @hide
23520 * @cfg {String} invalidClass @hide
23523 * @cfg {String} invalidText @hide
23526 * @cfg {String} msgFx @hide
23529 * @cfg {String} validateOnBlur @hide
23533 Roo.HtmlEditorCore.white = [
23534 'area', 'br', 'img', 'input', 'hr', 'wbr',
23536 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23537 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23538 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23539 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23540 'table', 'ul', 'xmp',
23542 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23545 'dir', 'menu', 'ol', 'ul', 'dl',
23551 Roo.HtmlEditorCore.black = [
23552 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23554 'base', 'basefont', 'bgsound', 'blink', 'body',
23555 'frame', 'frameset', 'head', 'html', 'ilayer',
23556 'iframe', 'layer', 'link', 'meta', 'object',
23557 'script', 'style' ,'title', 'xml' // clean later..
23559 Roo.HtmlEditorCore.clean = [
23560 'script', 'style', 'title', 'xml'
23562 Roo.HtmlEditorCore.remove = [
23567 Roo.HtmlEditorCore.ablack = [
23571 Roo.HtmlEditorCore.aclean = [
23572 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23576 Roo.HtmlEditorCore.pwhite= [
23577 'http', 'https', 'mailto'
23580 // white listed style attributes.
23581 Roo.HtmlEditorCore.cwhite= [
23582 // 'text-align', /// default is to allow most things..
23588 // black listed style attributes.
23589 Roo.HtmlEditorCore.cblack= [
23590 // 'font-size' -- this can be set by the project
23594 Roo.HtmlEditorCore.swapCodes =[
23613 * @class Roo.bootstrap.HtmlEditor
23614 * @extends Roo.bootstrap.TextArea
23615 * Bootstrap HtmlEditor class
23618 * Create a new HtmlEditor
23619 * @param {Object} config The config object
23622 Roo.bootstrap.HtmlEditor = function(config){
23623 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23624 if (!this.toolbars) {
23625 this.toolbars = [];
23628 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23631 * @event initialize
23632 * Fires when the editor is fully initialized (including the iframe)
23633 * @param {HtmlEditor} this
23638 * Fires when the editor is first receives the focus. Any insertion must wait
23639 * until after this event.
23640 * @param {HtmlEditor} this
23644 * @event beforesync
23645 * Fires before the textarea is updated with content from the editor iframe. Return false
23646 * to cancel the sync.
23647 * @param {HtmlEditor} this
23648 * @param {String} html
23652 * @event beforepush
23653 * Fires before the iframe editor is updated with content from the textarea. Return false
23654 * to cancel the push.
23655 * @param {HtmlEditor} this
23656 * @param {String} html
23661 * Fires when the textarea is updated with content from the editor iframe.
23662 * @param {HtmlEditor} this
23663 * @param {String} html
23668 * Fires when the iframe editor is updated with content from the textarea.
23669 * @param {HtmlEditor} this
23670 * @param {String} html
23674 * @event editmodechange
23675 * Fires when the editor switches edit modes
23676 * @param {HtmlEditor} this
23677 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23679 editmodechange: true,
23681 * @event editorevent
23682 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23683 * @param {HtmlEditor} this
23687 * @event firstfocus
23688 * Fires when on first focus - needed by toolbars..
23689 * @param {HtmlEditor} this
23694 * Auto save the htmlEditor value as a file into Events
23695 * @param {HtmlEditor} this
23699 * @event savedpreview
23700 * preview the saved version of htmlEditor
23701 * @param {HtmlEditor} this
23708 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23712 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23717 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23722 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23727 * @cfg {Number} height (in pixels)
23731 * @cfg {Number} width (in pixels)
23736 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23739 stylesheets: false,
23744 // private properties
23745 validationEvent : false,
23747 initialized : false,
23750 onFocus : Roo.emptyFn,
23752 hideMode:'offsets',
23754 tbContainer : false,
23758 toolbarContainer :function() {
23759 return this.wrap.select('.x-html-editor-tb',true).first();
23763 * Protected method that will not generally be called directly. It
23764 * is called when the editor creates its toolbar. Override this method if you need to
23765 * add custom toolbar buttons.
23766 * @param {HtmlEditor} editor
23768 createToolbar : function(){
23769 Roo.log('renewing');
23770 Roo.log("create toolbars");
23772 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23773 this.toolbars[0].render(this.toolbarContainer());
23777 // if (!editor.toolbars || !editor.toolbars.length) {
23778 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23781 // for (var i =0 ; i < editor.toolbars.length;i++) {
23782 // editor.toolbars[i] = Roo.factory(
23783 // typeof(editor.toolbars[i]) == 'string' ?
23784 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23785 // Roo.bootstrap.HtmlEditor);
23786 // editor.toolbars[i].init(editor);
23792 onRender : function(ct, position)
23794 // Roo.log("Call onRender: " + this.xtype);
23796 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23798 this.wrap = this.inputEl().wrap({
23799 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23802 this.editorcore.onRender(ct, position);
23804 if (this.resizable) {
23805 this.resizeEl = new Roo.Resizable(this.wrap, {
23809 minHeight : this.height,
23810 height: this.height,
23811 handles : this.resizable,
23814 resize : function(r, w, h) {
23815 _t.onResize(w,h); // -something
23821 this.createToolbar(this);
23824 if(!this.width && this.resizable){
23825 this.setSize(this.wrap.getSize());
23827 if (this.resizeEl) {
23828 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23829 // should trigger onReize..
23835 onResize : function(w, h)
23837 Roo.log('resize: ' +w + ',' + h );
23838 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23842 if(this.inputEl() ){
23843 if(typeof w == 'number'){
23844 var aw = w - this.wrap.getFrameWidth('lr');
23845 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23848 if(typeof h == 'number'){
23849 var tbh = -11; // fixme it needs to tool bar size!
23850 for (var i =0; i < this.toolbars.length;i++) {
23851 // fixme - ask toolbars for heights?
23852 tbh += this.toolbars[i].el.getHeight();
23853 //if (this.toolbars[i].footer) {
23854 // tbh += this.toolbars[i].footer.el.getHeight();
23862 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23863 ah -= 5; // knock a few pixes off for look..
23864 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23868 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23869 this.editorcore.onResize(ew,eh);
23874 * Toggles the editor between standard and source edit mode.
23875 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23877 toggleSourceEdit : function(sourceEditMode)
23879 this.editorcore.toggleSourceEdit(sourceEditMode);
23881 if(this.editorcore.sourceEditMode){
23882 Roo.log('editor - showing textarea');
23885 // Roo.log(this.syncValue());
23887 this.inputEl().removeClass(['hide', 'x-hidden']);
23888 this.inputEl().dom.removeAttribute('tabIndex');
23889 this.inputEl().focus();
23891 Roo.log('editor - hiding textarea');
23893 // Roo.log(this.pushValue());
23896 this.inputEl().addClass(['hide', 'x-hidden']);
23897 this.inputEl().dom.setAttribute('tabIndex', -1);
23898 //this.deferFocus();
23901 if(this.resizable){
23902 this.setSize(this.wrap.getSize());
23905 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23908 // private (for BoxComponent)
23909 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23911 // private (for BoxComponent)
23912 getResizeEl : function(){
23916 // private (for BoxComponent)
23917 getPositionEl : function(){
23922 initEvents : function(){
23923 this.originalValue = this.getValue();
23927 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23930 // markInvalid : Roo.emptyFn,
23932 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23935 // clearInvalid : Roo.emptyFn,
23937 setValue : function(v){
23938 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23939 this.editorcore.pushValue();
23944 deferFocus : function(){
23945 this.focus.defer(10, this);
23949 focus : function(){
23950 this.editorcore.focus();
23956 onDestroy : function(){
23962 for (var i =0; i < this.toolbars.length;i++) {
23963 // fixme - ask toolbars for heights?
23964 this.toolbars[i].onDestroy();
23967 this.wrap.dom.innerHTML = '';
23968 this.wrap.remove();
23973 onFirstFocus : function(){
23974 //Roo.log("onFirstFocus");
23975 this.editorcore.onFirstFocus();
23976 for (var i =0; i < this.toolbars.length;i++) {
23977 this.toolbars[i].onFirstFocus();
23983 syncValue : function()
23985 this.editorcore.syncValue();
23988 pushValue : function()
23990 this.editorcore.pushValue();
23994 // hide stuff that is not compatible
24008 * @event specialkey
24012 * @cfg {String} fieldClass @hide
24015 * @cfg {String} focusClass @hide
24018 * @cfg {String} autoCreate @hide
24021 * @cfg {String} inputType @hide
24025 * @cfg {String} invalidText @hide
24028 * @cfg {String} msgFx @hide
24031 * @cfg {String} validateOnBlur @hide
24040 Roo.namespace('Roo.bootstrap.htmleditor');
24042 * @class Roo.bootstrap.HtmlEditorToolbar1
24047 new Roo.bootstrap.HtmlEditor({
24050 new Roo.bootstrap.HtmlEditorToolbar1({
24051 disable : { fonts: 1 , format: 1, ..., ... , ...],
24057 * @cfg {Object} disable List of elements to disable..
24058 * @cfg {Array} btns List of additional buttons.
24062 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24065 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24068 Roo.apply(this, config);
24070 // default disabled, based on 'good practice'..
24071 this.disable = this.disable || {};
24072 Roo.applyIf(this.disable, {
24075 specialElements : true
24077 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24079 this.editor = config.editor;
24080 this.editorcore = config.editor.editorcore;
24082 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24084 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24085 // dont call parent... till later.
24087 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24092 editorcore : false,
24097 "h1","h2","h3","h4","h5","h6",
24099 "abbr", "acronym", "address", "cite", "samp", "var",
24103 onRender : function(ct, position)
24105 // Roo.log("Call onRender: " + this.xtype);
24107 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24109 this.el.dom.style.marginBottom = '0';
24111 var editorcore = this.editorcore;
24112 var editor= this.editor;
24115 var btn = function(id,cmd , toggle, handler, html){
24117 var event = toggle ? 'toggle' : 'click';
24122 xns: Roo.bootstrap,
24126 enableToggle:toggle !== false,
24128 pressed : toggle ? false : null,
24131 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24132 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24138 // var cb_box = function...
24143 xns: Roo.bootstrap,
24148 xns: Roo.bootstrap,
24152 Roo.each(this.formats, function(f) {
24153 style.menu.items.push({
24155 xns: Roo.bootstrap,
24156 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24161 editorcore.insertTag(this.tagname);
24168 children.push(style);
24170 btn('bold',false,true);
24171 btn('italic',false,true);
24172 btn('align-left', 'justifyleft',true);
24173 btn('align-center', 'justifycenter',true);
24174 btn('align-right' , 'justifyright',true);
24175 btn('link', false, false, function(btn) {
24176 //Roo.log("create link?");
24177 var url = prompt(this.createLinkText, this.defaultLinkValue);
24178 if(url && url != 'http:/'+'/'){
24179 this.editorcore.relayCmd('createlink', url);
24182 btn('list','insertunorderedlist',true);
24183 btn('pencil', false,true, function(btn){
24185 this.toggleSourceEdit(btn.pressed);
24188 if (this.editor.btns.length > 0) {
24189 for (var i = 0; i<this.editor.btns.length; i++) {
24190 children.push(this.editor.btns[i]);
24198 xns: Roo.bootstrap,
24203 xns: Roo.bootstrap,
24208 cog.menu.items.push({
24210 xns: Roo.bootstrap,
24211 html : Clean styles,
24216 editorcore.insertTag(this.tagname);
24225 this.xtype = 'NavSimplebar';
24227 for(var i=0;i< children.length;i++) {
24229 this.buttons.add(this.addxtypeChild(children[i]));
24233 editor.on('editorevent', this.updateToolbar, this);
24235 onBtnClick : function(id)
24237 this.editorcore.relayCmd(id);
24238 this.editorcore.focus();
24242 * Protected method that will not generally be called directly. It triggers
24243 * a toolbar update by reading the markup state of the current selection in the editor.
24245 updateToolbar: function(){
24247 if(!this.editorcore.activated){
24248 this.editor.onFirstFocus(); // is this neeed?
24252 var btns = this.buttons;
24253 var doc = this.editorcore.doc;
24254 btns.get('bold').setActive(doc.queryCommandState('bold'));
24255 btns.get('italic').setActive(doc.queryCommandState('italic'));
24256 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24258 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24259 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24260 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24262 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24263 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24266 var ans = this.editorcore.getAllAncestors();
24267 if (this.formatCombo) {
24270 var store = this.formatCombo.store;
24271 this.formatCombo.setValue("");
24272 for (var i =0; i < ans.length;i++) {
24273 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24275 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24283 // hides menus... - so this cant be on a menu...
24284 Roo.bootstrap.MenuMgr.hideAll();
24286 Roo.bootstrap.MenuMgr.hideAll();
24287 //this.editorsyncValue();
24289 onFirstFocus: function() {
24290 this.buttons.each(function(item){
24294 toggleSourceEdit : function(sourceEditMode){
24297 if(sourceEditMode){
24298 Roo.log("disabling buttons");
24299 this.buttons.each( function(item){
24300 if(item.cmd != 'pencil'){
24306 Roo.log("enabling buttons");
24307 if(this.editorcore.initialized){
24308 this.buttons.each( function(item){
24314 Roo.log("calling toggole on editor");
24315 // tell the editor that it's been pressed..
24316 this.editor.toggleSourceEdit(sourceEditMode);
24326 * @class Roo.bootstrap.Table.AbstractSelectionModel
24327 * @extends Roo.util.Observable
24328 * Abstract base class for grid SelectionModels. It provides the interface that should be
24329 * implemented by descendant classes. This class should not be directly instantiated.
24332 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24333 this.locked = false;
24334 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24338 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24339 /** @ignore Called by the grid automatically. Do not call directly. */
24340 init : function(grid){
24346 * Locks the selections.
24349 this.locked = true;
24353 * Unlocks the selections.
24355 unlock : function(){
24356 this.locked = false;
24360 * Returns true if the selections are locked.
24361 * @return {Boolean}
24363 isLocked : function(){
24364 return this.locked;
24368 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24369 * @class Roo.bootstrap.Table.RowSelectionModel
24370 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24371 * It supports multiple selections and keyboard selection/navigation.
24373 * @param {Object} config
24376 Roo.bootstrap.Table.RowSelectionModel = function(config){
24377 Roo.apply(this, config);
24378 this.selections = new Roo.util.MixedCollection(false, function(o){
24383 this.lastActive = false;
24387 * @event selectionchange
24388 * Fires when the selection changes
24389 * @param {SelectionModel} this
24391 "selectionchange" : true,
24393 * @event afterselectionchange
24394 * Fires after the selection changes (eg. by key press or clicking)
24395 * @param {SelectionModel} this
24397 "afterselectionchange" : true,
24399 * @event beforerowselect
24400 * Fires when a row is selected being selected, return false to cancel.
24401 * @param {SelectionModel} this
24402 * @param {Number} rowIndex The selected index
24403 * @param {Boolean} keepExisting False if other selections will be cleared
24405 "beforerowselect" : true,
24408 * Fires when a row is selected.
24409 * @param {SelectionModel} this
24410 * @param {Number} rowIndex The selected index
24411 * @param {Roo.data.Record} r The record
24413 "rowselect" : true,
24415 * @event rowdeselect
24416 * Fires when a row is deselected.
24417 * @param {SelectionModel} this
24418 * @param {Number} rowIndex The selected index
24420 "rowdeselect" : true
24422 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24423 this.locked = false;
24426 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24428 * @cfg {Boolean} singleSelect
24429 * True to allow selection of only one row at a time (defaults to false)
24431 singleSelect : false,
24434 initEvents : function()
24437 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24438 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24439 //}else{ // allow click to work like normal
24440 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24442 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24443 this.grid.on("rowclick", this.handleMouseDown, this);
24445 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24446 "up" : function(e){
24448 this.selectPrevious(e.shiftKey);
24449 }else if(this.last !== false && this.lastActive !== false){
24450 var last = this.last;
24451 this.selectRange(this.last, this.lastActive-1);
24452 this.grid.getView().focusRow(this.lastActive);
24453 if(last !== false){
24457 this.selectFirstRow();
24459 this.fireEvent("afterselectionchange", this);
24461 "down" : function(e){
24463 this.selectNext(e.shiftKey);
24464 }else if(this.last !== false && this.lastActive !== false){
24465 var last = this.last;
24466 this.selectRange(this.last, this.lastActive+1);
24467 this.grid.getView().focusRow(this.lastActive);
24468 if(last !== false){
24472 this.selectFirstRow();
24474 this.fireEvent("afterselectionchange", this);
24478 this.grid.store.on('load', function(){
24479 this.selections.clear();
24482 var view = this.grid.view;
24483 view.on("refresh", this.onRefresh, this);
24484 view.on("rowupdated", this.onRowUpdated, this);
24485 view.on("rowremoved", this.onRemove, this);
24490 onRefresh : function()
24492 var ds = this.grid.store, i, v = this.grid.view;
24493 var s = this.selections;
24494 s.each(function(r){
24495 if((i = ds.indexOfId(r.id)) != -1){
24504 onRemove : function(v, index, r){
24505 this.selections.remove(r);
24509 onRowUpdated : function(v, index, r){
24510 if(this.isSelected(r)){
24511 v.onRowSelect(index);
24517 * @param {Array} records The records to select
24518 * @param {Boolean} keepExisting (optional) True to keep existing selections
24520 selectRecords : function(records, keepExisting)
24523 this.clearSelections();
24525 var ds = this.grid.store;
24526 for(var i = 0, len = records.length; i < len; i++){
24527 this.selectRow(ds.indexOf(records[i]), true);
24532 * Gets the number of selected rows.
24535 getCount : function(){
24536 return this.selections.length;
24540 * Selects the first row in the grid.
24542 selectFirstRow : function(){
24547 * Select the last row.
24548 * @param {Boolean} keepExisting (optional) True to keep existing selections
24550 selectLastRow : function(keepExisting){
24551 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24552 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24556 * Selects the row immediately following the last selected row.
24557 * @param {Boolean} keepExisting (optional) True to keep existing selections
24559 selectNext : function(keepExisting)
24561 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24562 this.selectRow(this.last+1, keepExisting);
24563 this.grid.getView().focusRow(this.last);
24568 * Selects the row that precedes the last selected row.
24569 * @param {Boolean} keepExisting (optional) True to keep existing selections
24571 selectPrevious : function(keepExisting){
24573 this.selectRow(this.last-1, keepExisting);
24574 this.grid.getView().focusRow(this.last);
24579 * Returns the selected records
24580 * @return {Array} Array of selected records
24582 getSelections : function(){
24583 return [].concat(this.selections.items);
24587 * Returns the first selected record.
24590 getSelected : function(){
24591 return this.selections.itemAt(0);
24596 * Clears all selections.
24598 clearSelections : function(fast)
24604 var ds = this.grid.store;
24605 var s = this.selections;
24606 s.each(function(r){
24607 this.deselectRow(ds.indexOfId(r.id));
24611 this.selections.clear();
24618 * Selects all rows.
24620 selectAll : function(){
24624 this.selections.clear();
24625 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24626 this.selectRow(i, true);
24631 * Returns True if there is a selection.
24632 * @return {Boolean}
24634 hasSelection : function(){
24635 return this.selections.length > 0;
24639 * Returns True if the specified row is selected.
24640 * @param {Number/Record} record The record or index of the record to check
24641 * @return {Boolean}
24643 isSelected : function(index){
24644 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24645 return (r && this.selections.key(r.id) ? true : false);
24649 * Returns True if the specified record id is selected.
24650 * @param {String} id The id of record to check
24651 * @return {Boolean}
24653 isIdSelected : function(id){
24654 return (this.selections.key(id) ? true : false);
24659 handleMouseDBClick : function(e, t){
24663 handleMouseDown : function(e, t)
24665 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24666 if(this.isLocked() || rowIndex < 0 ){
24669 if(e.shiftKey && this.last !== false){
24670 var last = this.last;
24671 this.selectRange(last, rowIndex, e.ctrlKey);
24672 this.last = last; // reset the last
24676 var isSelected = this.isSelected(rowIndex);
24677 //Roo.log("select row:" + rowIndex);
24679 this.deselectRow(rowIndex);
24681 this.selectRow(rowIndex, true);
24685 if(e.button !== 0 && isSelected){
24686 alert('rowIndex 2: ' + rowIndex);
24687 view.focusRow(rowIndex);
24688 }else if(e.ctrlKey && isSelected){
24689 this.deselectRow(rowIndex);
24690 }else if(!isSelected){
24691 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24692 view.focusRow(rowIndex);
24696 this.fireEvent("afterselectionchange", this);
24699 handleDragableRowClick : function(grid, rowIndex, e)
24701 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24702 this.selectRow(rowIndex, false);
24703 grid.view.focusRow(rowIndex);
24704 this.fireEvent("afterselectionchange", this);
24709 * Selects multiple rows.
24710 * @param {Array} rows Array of the indexes of the row to select
24711 * @param {Boolean} keepExisting (optional) True to keep existing selections
24713 selectRows : function(rows, keepExisting){
24715 this.clearSelections();
24717 for(var i = 0, len = rows.length; i < len; i++){
24718 this.selectRow(rows[i], true);
24723 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24724 * @param {Number} startRow The index of the first row in the range
24725 * @param {Number} endRow The index of the last row in the range
24726 * @param {Boolean} keepExisting (optional) True to retain existing selections
24728 selectRange : function(startRow, endRow, keepExisting){
24733 this.clearSelections();
24735 if(startRow <= endRow){
24736 for(var i = startRow; i <= endRow; i++){
24737 this.selectRow(i, true);
24740 for(var i = startRow; i >= endRow; i--){
24741 this.selectRow(i, true);
24747 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24748 * @param {Number} startRow The index of the first row in the range
24749 * @param {Number} endRow The index of the last row in the range
24751 deselectRange : function(startRow, endRow, preventViewNotify){
24755 for(var i = startRow; i <= endRow; i++){
24756 this.deselectRow(i, preventViewNotify);
24762 * @param {Number} row The index of the row to select
24763 * @param {Boolean} keepExisting (optional) True to keep existing selections
24765 selectRow : function(index, keepExisting, preventViewNotify)
24767 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24770 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24771 if(!keepExisting || this.singleSelect){
24772 this.clearSelections();
24775 var r = this.grid.store.getAt(index);
24776 //console.log('selectRow - record id :' + r.id);
24778 this.selections.add(r);
24779 this.last = this.lastActive = index;
24780 if(!preventViewNotify){
24781 var proxy = new Roo.Element(
24782 this.grid.getRowDom(index)
24784 proxy.addClass('bg-info info');
24786 this.fireEvent("rowselect", this, index, r);
24787 this.fireEvent("selectionchange", this);
24793 * @param {Number} row The index of the row to deselect
24795 deselectRow : function(index, preventViewNotify)
24800 if(this.last == index){
24803 if(this.lastActive == index){
24804 this.lastActive = false;
24807 var r = this.grid.store.getAt(index);
24812 this.selections.remove(r);
24813 //.console.log('deselectRow - record id :' + r.id);
24814 if(!preventViewNotify){
24816 var proxy = new Roo.Element(
24817 this.grid.getRowDom(index)
24819 proxy.removeClass('bg-info info');
24821 this.fireEvent("rowdeselect", this, index);
24822 this.fireEvent("selectionchange", this);
24826 restoreLast : function(){
24828 this.last = this._last;
24833 acceptsNav : function(row, col, cm){
24834 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24838 onEditorKey : function(field, e){
24839 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24844 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24846 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24848 }else if(k == e.ENTER && !e.ctrlKey){
24852 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24854 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24856 }else if(k == e.ESC){
24860 g.startEditing(newCell[0], newCell[1]);
24866 * Ext JS Library 1.1.1
24867 * Copyright(c) 2006-2007, Ext JS, LLC.
24869 * Originally Released Under LGPL - original licence link has changed is not relivant.
24872 * <script type="text/javascript">
24876 * @class Roo.bootstrap.PagingToolbar
24877 * @extends Roo.bootstrap.NavSimplebar
24878 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24880 * Create a new PagingToolbar
24881 * @param {Object} config The config object
24882 * @param {Roo.data.Store} store
24884 Roo.bootstrap.PagingToolbar = function(config)
24886 // old args format still supported... - xtype is prefered..
24887 // created from xtype...
24889 this.ds = config.dataSource;
24891 if (config.store && !this.ds) {
24892 this.store= Roo.factory(config.store, Roo.data);
24893 this.ds = this.store;
24894 this.ds.xmodule = this.xmodule || false;
24897 this.toolbarItems = [];
24898 if (config.items) {
24899 this.toolbarItems = config.items;
24902 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24907 this.bind(this.ds);
24910 if (Roo.bootstrap.version == 4) {
24911 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24913 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24918 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24920 * @cfg {Roo.data.Store} dataSource
24921 * The underlying data store providing the paged data
24924 * @cfg {String/HTMLElement/Element} container
24925 * container The id or element that will contain the toolbar
24928 * @cfg {Boolean} displayInfo
24929 * True to display the displayMsg (defaults to false)
24932 * @cfg {Number} pageSize
24933 * The number of records to display per page (defaults to 20)
24937 * @cfg {String} displayMsg
24938 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24940 displayMsg : 'Displaying {0} - {1} of {2}',
24942 * @cfg {String} emptyMsg
24943 * The message to display when no records are found (defaults to "No data to display")
24945 emptyMsg : 'No data to display',
24947 * Customizable piece of the default paging text (defaults to "Page")
24950 beforePageText : "Page",
24952 * Customizable piece of the default paging text (defaults to "of %0")
24955 afterPageText : "of {0}",
24957 * Customizable piece of the default paging text (defaults to "First Page")
24960 firstText : "First Page",
24962 * Customizable piece of the default paging text (defaults to "Previous Page")
24965 prevText : "Previous Page",
24967 * Customizable piece of the default paging text (defaults to "Next Page")
24970 nextText : "Next Page",
24972 * Customizable piece of the default paging text (defaults to "Last Page")
24975 lastText : "Last Page",
24977 * Customizable piece of the default paging text (defaults to "Refresh")
24980 refreshText : "Refresh",
24984 onRender : function(ct, position)
24986 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24987 this.navgroup.parentId = this.id;
24988 this.navgroup.onRender(this.el, null);
24989 // add the buttons to the navgroup
24991 if(this.displayInfo){
24992 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24993 this.displayEl = this.el.select('.x-paging-info', true).first();
24994 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24995 // this.displayEl = navel.el.select('span',true).first();
25001 Roo.each(_this.buttons, function(e){ // this might need to use render????
25002 Roo.factory(e).render(_this.el);
25006 Roo.each(_this.toolbarItems, function(e) {
25007 _this.navgroup.addItem(e);
25011 this.first = this.navgroup.addItem({
25012 tooltip: this.firstText,
25013 cls: "prev btn-outline-secondary",
25014 html : ' <i class="fa fa-step-backward"></i>',
25016 preventDefault: true,
25017 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25020 this.prev = this.navgroup.addItem({
25021 tooltip: this.prevText,
25022 cls: "prev btn-outline-secondary",
25023 html : ' <i class="fa fa-backward"></i>',
25025 preventDefault: true,
25026 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25028 //this.addSeparator();
25031 var field = this.navgroup.addItem( {
25033 cls : 'x-paging-position btn-outline-secondary',
25035 html : this.beforePageText +
25036 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25037 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25040 this.field = field.el.select('input', true).first();
25041 this.field.on("keydown", this.onPagingKeydown, this);
25042 this.field.on("focus", function(){this.dom.select();});
25045 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25046 //this.field.setHeight(18);
25047 //this.addSeparator();
25048 this.next = this.navgroup.addItem({
25049 tooltip: this.nextText,
25050 cls: "next btn-outline-secondary",
25051 html : ' <i class="fa fa-forward"></i>',
25053 preventDefault: true,
25054 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25056 this.last = this.navgroup.addItem({
25057 tooltip: this.lastText,
25058 html : ' <i class="fa fa-step-forward"></i>',
25059 cls: "next btn-outline-secondary",
25061 preventDefault: true,
25062 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25064 //this.addSeparator();
25065 this.loading = this.navgroup.addItem({
25066 tooltip: this.refreshText,
25067 cls: "btn-outline-secondary",
25068 html : ' <i class="fa fa-refresh"></i>',
25069 preventDefault: true,
25070 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25076 updateInfo : function(){
25077 if(this.displayEl){
25078 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25079 var msg = count == 0 ?
25083 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25085 this.displayEl.update(msg);
25090 onLoad : function(ds, r, o)
25092 this.cursor = o.params.start ? o.params.start : 0;
25094 var d = this.getPageData(),
25099 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25100 this.field.dom.value = ap;
25101 this.first.setDisabled(ap == 1);
25102 this.prev.setDisabled(ap == 1);
25103 this.next.setDisabled(ap == ps);
25104 this.last.setDisabled(ap == ps);
25105 this.loading.enable();
25110 getPageData : function(){
25111 var total = this.ds.getTotalCount();
25114 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25115 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25120 onLoadError : function(){
25121 this.loading.enable();
25125 onPagingKeydown : function(e){
25126 var k = e.getKey();
25127 var d = this.getPageData();
25129 var v = this.field.dom.value, pageNum;
25130 if(!v || isNaN(pageNum = parseInt(v, 10))){
25131 this.field.dom.value = d.activePage;
25134 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25135 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25138 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
25140 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25141 this.field.dom.value = pageNum;
25142 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25145 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25147 var v = this.field.dom.value, pageNum;
25148 var increment = (e.shiftKey) ? 10 : 1;
25149 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25152 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25153 this.field.dom.value = d.activePage;
25156 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25158 this.field.dom.value = parseInt(v, 10) + increment;
25159 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25160 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25167 beforeLoad : function(){
25169 this.loading.disable();
25174 onClick : function(which){
25183 ds.load({params:{start: 0, limit: this.pageSize}});
25186 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25189 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25192 var total = ds.getTotalCount();
25193 var extra = total % this.pageSize;
25194 var lastStart = extra ? (total - extra) : total-this.pageSize;
25195 ds.load({params:{start: lastStart, limit: this.pageSize}});
25198 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25204 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25205 * @param {Roo.data.Store} store The data store to unbind
25207 unbind : function(ds){
25208 ds.un("beforeload", this.beforeLoad, this);
25209 ds.un("load", this.onLoad, this);
25210 ds.un("loadexception", this.onLoadError, this);
25211 ds.un("remove", this.updateInfo, this);
25212 ds.un("add", this.updateInfo, this);
25213 this.ds = undefined;
25217 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25218 * @param {Roo.data.Store} store The data store to bind
25220 bind : function(ds){
25221 ds.on("beforeload", this.beforeLoad, this);
25222 ds.on("load", this.onLoad, this);
25223 ds.on("loadexception", this.onLoadError, this);
25224 ds.on("remove", this.updateInfo, this);
25225 ds.on("add", this.updateInfo, this);
25236 * @class Roo.bootstrap.MessageBar
25237 * @extends Roo.bootstrap.Component
25238 * Bootstrap MessageBar class
25239 * @cfg {String} html contents of the MessageBar
25240 * @cfg {String} weight (info | success | warning | danger) default info
25241 * @cfg {String} beforeClass insert the bar before the given class
25242 * @cfg {Boolean} closable (true | false) default false
25243 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25246 * Create a new Element
25247 * @param {Object} config The config object
25250 Roo.bootstrap.MessageBar = function(config){
25251 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25254 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25260 beforeClass: 'bootstrap-sticky-wrap',
25262 getAutoCreate : function(){
25266 cls: 'alert alert-dismissable alert-' + this.weight,
25271 html: this.html || ''
25277 cfg.cls += ' alert-messages-fixed';
25291 onRender : function(ct, position)
25293 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25296 var cfg = Roo.apply({}, this.getAutoCreate());
25300 cfg.cls += ' ' + this.cls;
25303 cfg.style = this.style;
25305 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25307 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25310 this.el.select('>button.close').on('click', this.hide, this);
25316 if (!this.rendered) {
25322 this.fireEvent('show', this);
25328 if (!this.rendered) {
25334 this.fireEvent('hide', this);
25337 update : function()
25339 // var e = this.el.dom.firstChild;
25341 // if(this.closable){
25342 // e = e.nextSibling;
25345 // e.data = this.html || '';
25347 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25363 * @class Roo.bootstrap.Graph
25364 * @extends Roo.bootstrap.Component
25365 * Bootstrap Graph class
25369 @cfg {String} graphtype bar | vbar | pie
25370 @cfg {number} g_x coodinator | centre x (pie)
25371 @cfg {number} g_y coodinator | centre y (pie)
25372 @cfg {number} g_r radius (pie)
25373 @cfg {number} g_height height of the chart (respected by all elements in the set)
25374 @cfg {number} g_width width of the chart (respected by all elements in the set)
25375 @cfg {Object} title The title of the chart
25378 -opts (object) options for the chart
25380 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25381 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25383 o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
25384 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25386 o stretch (boolean)
25388 -opts (object) options for the pie
25391 o startAngle (number)
25392 o endAngle (number)
25396 * Create a new Input
25397 * @param {Object} config The config object
25400 Roo.bootstrap.Graph = function(config){
25401 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25407 * The img click event for the img.
25408 * @param {Roo.EventObject} e
25414 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25425 //g_colors: this.colors,
25432 getAutoCreate : function(){
25443 onRender : function(ct,position){
25446 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25448 if (typeof(Raphael) == 'undefined') {
25449 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25453 this.raphael = Raphael(this.el.dom);
25455 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25456 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25457 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25458 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25460 r.text(160, 10, "Single Series Chart").attr(txtattr);
25461 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25462 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25463 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25465 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25466 r.barchart(330, 10, 300, 220, data1);
25467 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25468 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25471 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25472 // r.barchart(30, 30, 560, 250, xdata, {
25473 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25474 // axis : "0 0 1 1",
25475 // axisxlabels : xdata
25476 // //yvalues : cols,
25479 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25481 // this.load(null,xdata,{
25482 // axis : "0 0 1 1",
25483 // axisxlabels : xdata
25488 load : function(graphtype,xdata,opts)
25490 this.raphael.clear();
25492 graphtype = this.graphtype;
25497 var r = this.raphael,
25498 fin = function () {
25499 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25501 fout = function () {
25502 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25504 pfin = function() {
25505 this.sector.stop();
25506 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25509 this.label[0].stop();
25510 this.label[0].attr({ r: 7.5 });
25511 this.label[1].attr({ "font-weight": 800 });
25514 pfout = function() {
25515 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25518 this.label[0].animate({ r: 5 }, 500, "bounce");
25519 this.label[1].attr({ "font-weight": 400 });
25525 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25528 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25531 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25532 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25534 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25541 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25546 setTitle: function(o)
25551 initEvents: function() {
25554 this.el.on('click', this.onClick, this);
25558 onClick : function(e)
25560 Roo.log('img onclick');
25561 this.fireEvent('click', this, e);
25573 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25576 * @class Roo.bootstrap.dash.NumberBox
25577 * @extends Roo.bootstrap.Component
25578 * Bootstrap NumberBox class
25579 * @cfg {String} headline Box headline
25580 * @cfg {String} content Box content
25581 * @cfg {String} icon Box icon
25582 * @cfg {String} footer Footer text
25583 * @cfg {String} fhref Footer href
25586 * Create a new NumberBox
25587 * @param {Object} config The config object
25591 Roo.bootstrap.dash.NumberBox = function(config){
25592 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25596 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25605 getAutoCreate : function(){
25609 cls : 'small-box ',
25617 cls : 'roo-headline',
25618 html : this.headline
25622 cls : 'roo-content',
25623 html : this.content
25637 cls : 'ion ' + this.icon
25646 cls : 'small-box-footer',
25647 href : this.fhref || '#',
25651 cfg.cn.push(footer);
25658 onRender : function(ct,position){
25659 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25666 setHeadline: function (value)
25668 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25671 setFooter: function (value, href)
25673 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25676 this.el.select('a.small-box-footer',true).first().attr('href', href);
25681 setContent: function (value)
25683 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25686 initEvents: function()
25700 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25703 * @class Roo.bootstrap.dash.TabBox
25704 * @extends Roo.bootstrap.Component
25705 * Bootstrap TabBox class
25706 * @cfg {String} title Title of the TabBox
25707 * @cfg {String} icon Icon of the TabBox
25708 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25709 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25712 * Create a new TabBox
25713 * @param {Object} config The config object
25717 Roo.bootstrap.dash.TabBox = function(config){
25718 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25723 * When a pane is added
25724 * @param {Roo.bootstrap.dash.TabPane} pane
25728 * @event activatepane
25729 * When a pane is activated
25730 * @param {Roo.bootstrap.dash.TabPane} pane
25732 "activatepane" : true
25740 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25745 tabScrollable : false,
25747 getChildContainer : function()
25749 return this.el.select('.tab-content', true).first();
25752 getAutoCreate : function(){
25756 cls: 'pull-left header',
25764 cls: 'fa ' + this.icon
25770 cls: 'nav nav-tabs pull-right',
25776 if(this.tabScrollable){
25783 cls: 'nav nav-tabs pull-right',
25794 cls: 'nav-tabs-custom',
25799 cls: 'tab-content no-padding',
25807 initEvents : function()
25809 //Roo.log('add add pane handler');
25810 this.on('addpane', this.onAddPane, this);
25813 * Updates the box title
25814 * @param {String} html to set the title to.
25816 setTitle : function(value)
25818 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25820 onAddPane : function(pane)
25822 this.panes.push(pane);
25823 //Roo.log('addpane');
25825 // tabs are rendere left to right..
25826 if(!this.showtabs){
25830 var ctr = this.el.select('.nav-tabs', true).first();
25833 var existing = ctr.select('.nav-tab',true);
25834 var qty = existing.getCount();;
25837 var tab = ctr.createChild({
25839 cls : 'nav-tab' + (qty ? '' : ' active'),
25847 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25850 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25852 pane.el.addClass('active');
25857 onTabClick : function(ev,un,ob,pane)
25859 //Roo.log('tab - prev default');
25860 ev.preventDefault();
25863 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25864 pane.tab.addClass('active');
25865 //Roo.log(pane.title);
25866 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25867 // technically we should have a deactivate event.. but maybe add later.
25868 // and it should not de-activate the selected tab...
25869 this.fireEvent('activatepane', pane);
25870 pane.el.addClass('active');
25871 pane.fireEvent('activate');
25876 getActivePane : function()
25879 Roo.each(this.panes, function(p) {
25880 if(p.el.hasClass('active')){
25901 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25903 * @class Roo.bootstrap.TabPane
25904 * @extends Roo.bootstrap.Component
25905 * Bootstrap TabPane class
25906 * @cfg {Boolean} active (false | true) Default false
25907 * @cfg {String} title title of panel
25911 * Create a new TabPane
25912 * @param {Object} config The config object
25915 Roo.bootstrap.dash.TabPane = function(config){
25916 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25922 * When a pane is activated
25923 * @param {Roo.bootstrap.dash.TabPane} pane
25930 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25935 // the tabBox that this is attached to.
25938 getAutoCreate : function()
25946 cfg.cls += ' active';
25951 initEvents : function()
25953 //Roo.log('trigger add pane handler');
25954 this.parent().fireEvent('addpane', this)
25958 * Updates the tab title
25959 * @param {String} html to set the title to.
25961 setTitle: function(str)
25967 this.tab.select('a', true).first().dom.innerHTML = str;
25984 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25987 * @class Roo.bootstrap.menu.Menu
25988 * @extends Roo.bootstrap.Component
25989 * Bootstrap Menu class - container for Menu
25990 * @cfg {String} html Text of the menu
25991 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25992 * @cfg {String} icon Font awesome icon
25993 * @cfg {String} pos Menu align to (top | bottom) default bottom
25997 * Create a new Menu
25998 * @param {Object} config The config object
26002 Roo.bootstrap.menu.Menu = function(config){
26003 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26007 * @event beforeshow
26008 * Fires before this menu is displayed
26009 * @param {Roo.bootstrap.menu.Menu} this
26013 * @event beforehide
26014 * Fires before this menu is hidden
26015 * @param {Roo.bootstrap.menu.Menu} this
26020 * Fires after this menu is displayed
26021 * @param {Roo.bootstrap.menu.Menu} this
26026 * Fires after this menu is hidden
26027 * @param {Roo.bootstrap.menu.Menu} this
26032 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26033 * @param {Roo.bootstrap.menu.Menu} this
26034 * @param {Roo.EventObject} e
26041 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26045 weight : 'default',
26050 getChildContainer : function() {
26051 if(this.isSubMenu){
26055 return this.el.select('ul.dropdown-menu', true).first();
26058 getAutoCreate : function()
26063 cls : 'roo-menu-text',
26071 cls : 'fa ' + this.icon
26082 cls : 'dropdown-button btn btn-' + this.weight,
26087 cls : 'dropdown-toggle btn btn-' + this.weight,
26097 cls : 'dropdown-menu'
26103 if(this.pos == 'top'){
26104 cfg.cls += ' dropup';
26107 if(this.isSubMenu){
26110 cls : 'dropdown-menu'
26117 onRender : function(ct, position)
26119 this.isSubMenu = ct.hasClass('dropdown-submenu');
26121 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26124 initEvents : function()
26126 if(this.isSubMenu){
26130 this.hidden = true;
26132 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26133 this.triggerEl.on('click', this.onTriggerPress, this);
26135 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26136 this.buttonEl.on('click', this.onClick, this);
26142 if(this.isSubMenu){
26146 return this.el.select('ul.dropdown-menu', true).first();
26149 onClick : function(e)
26151 this.fireEvent("click", this, e);
26154 onTriggerPress : function(e)
26156 if (this.isVisible()) {
26163 isVisible : function(){
26164 return !this.hidden;
26169 this.fireEvent("beforeshow", this);
26171 this.hidden = false;
26172 this.el.addClass('open');
26174 Roo.get(document).on("mouseup", this.onMouseUp, this);
26176 this.fireEvent("show", this);
26183 this.fireEvent("beforehide", this);
26185 this.hidden = true;
26186 this.el.removeClass('open');
26188 Roo.get(document).un("mouseup", this.onMouseUp);
26190 this.fireEvent("hide", this);
26193 onMouseUp : function()
26207 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26210 * @class Roo.bootstrap.menu.Item
26211 * @extends Roo.bootstrap.Component
26212 * Bootstrap MenuItem class
26213 * @cfg {Boolean} submenu (true | false) default false
26214 * @cfg {String} html text of the item
26215 * @cfg {String} href the link
26216 * @cfg {Boolean} disable (true | false) default false
26217 * @cfg {Boolean} preventDefault (true | false) default true
26218 * @cfg {String} icon Font awesome icon
26219 * @cfg {String} pos Submenu align to (left | right) default right
26223 * Create a new Item
26224 * @param {Object} config The config object
26228 Roo.bootstrap.menu.Item = function(config){
26229 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26233 * Fires when the mouse is hovering over this menu
26234 * @param {Roo.bootstrap.menu.Item} this
26235 * @param {Roo.EventObject} e
26240 * Fires when the mouse exits this menu
26241 * @param {Roo.bootstrap.menu.Item} this
26242 * @param {Roo.EventObject} e
26248 * The raw click event for the entire grid.
26249 * @param {Roo.EventObject} e
26255 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26260 preventDefault: true,
26265 getAutoCreate : function()
26270 cls : 'roo-menu-item-text',
26278 cls : 'fa ' + this.icon
26287 href : this.href || '#',
26294 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26298 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26300 if(this.pos == 'left'){
26301 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26308 initEvents : function()
26310 this.el.on('mouseover', this.onMouseOver, this);
26311 this.el.on('mouseout', this.onMouseOut, this);
26313 this.el.select('a', true).first().on('click', this.onClick, this);
26317 onClick : function(e)
26319 if(this.preventDefault){
26320 e.preventDefault();
26323 this.fireEvent("click", this, e);
26326 onMouseOver : function(e)
26328 if(this.submenu && this.pos == 'left'){
26329 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26332 this.fireEvent("mouseover", this, e);
26335 onMouseOut : function(e)
26337 this.fireEvent("mouseout", this, e);
26349 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26352 * @class Roo.bootstrap.menu.Separator
26353 * @extends Roo.bootstrap.Component
26354 * Bootstrap Separator class
26357 * Create a new Separator
26358 * @param {Object} config The config object
26362 Roo.bootstrap.menu.Separator = function(config){
26363 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26366 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26368 getAutoCreate : function(){
26389 * @class Roo.bootstrap.Tooltip
26390 * Bootstrap Tooltip class
26391 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26392 * to determine which dom element triggers the tooltip.
26394 * It needs to add support for additional attributes like tooltip-position
26397 * Create a new Toolti
26398 * @param {Object} config The config object
26401 Roo.bootstrap.Tooltip = function(config){
26402 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26404 this.alignment = Roo.bootstrap.Tooltip.alignment;
26406 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26407 this.alignment = config.alignment;
26412 Roo.apply(Roo.bootstrap.Tooltip, {
26414 * @function init initialize tooltip monitoring.
26418 currentTip : false,
26419 currentRegion : false,
26425 Roo.get(document).on('mouseover', this.enter ,this);
26426 Roo.get(document).on('mouseout', this.leave, this);
26429 this.currentTip = new Roo.bootstrap.Tooltip();
26432 enter : function(ev)
26434 var dom = ev.getTarget();
26436 //Roo.log(['enter',dom]);
26437 var el = Roo.fly(dom);
26438 if (this.currentEl) {
26440 //Roo.log(this.currentEl);
26441 //Roo.log(this.currentEl.contains(dom));
26442 if (this.currentEl == el) {
26445 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26451 if (this.currentTip.el) {
26452 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26456 if(!el || el.dom == document){
26462 // you can not look for children, as if el is the body.. then everythign is the child..
26463 if (!el.attr('tooltip')) { //
26464 if (!el.select("[tooltip]").elements.length) {
26467 // is the mouse over this child...?
26468 bindEl = el.select("[tooltip]").first();
26469 var xy = ev.getXY();
26470 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26471 //Roo.log("not in region.");
26474 //Roo.log("child element over..");
26477 this.currentEl = bindEl;
26478 this.currentTip.bind(bindEl);
26479 this.currentRegion = Roo.lib.Region.getRegion(dom);
26480 this.currentTip.enter();
26483 leave : function(ev)
26485 var dom = ev.getTarget();
26486 //Roo.log(['leave',dom]);
26487 if (!this.currentEl) {
26492 if (dom != this.currentEl.dom) {
26495 var xy = ev.getXY();
26496 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26499 // only activate leave if mouse cursor is outside... bounding box..
26504 if (this.currentTip) {
26505 this.currentTip.leave();
26507 //Roo.log('clear currentEl');
26508 this.currentEl = false;
26513 'left' : ['r-l', [-2,0], 'right'],
26514 'right' : ['l-r', [2,0], 'left'],
26515 'bottom' : ['t-b', [0,2], 'top'],
26516 'top' : [ 'b-t', [0,-2], 'bottom']
26522 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26527 delay : null, // can be { show : 300 , hide: 500}
26531 hoverState : null, //???
26533 placement : 'bottom',
26537 getAutoCreate : function(){
26544 cls : 'tooltip-arrow'
26547 cls : 'tooltip-inner'
26554 bind : function(el)
26560 enter : function () {
26562 if (this.timeout != null) {
26563 clearTimeout(this.timeout);
26566 this.hoverState = 'in';
26567 //Roo.log("enter - show");
26568 if (!this.delay || !this.delay.show) {
26573 this.timeout = setTimeout(function () {
26574 if (_t.hoverState == 'in') {
26577 }, this.delay.show);
26581 clearTimeout(this.timeout);
26583 this.hoverState = 'out';
26584 if (!this.delay || !this.delay.hide) {
26590 this.timeout = setTimeout(function () {
26591 //Roo.log("leave - timeout");
26593 if (_t.hoverState == 'out') {
26595 Roo.bootstrap.Tooltip.currentEl = false;
26600 show : function (msg)
26603 this.render(document.body);
26606 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26608 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26610 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26612 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26614 var placement = typeof this.placement == 'function' ?
26615 this.placement.call(this, this.el, on_el) :
26618 var autoToken = /\s?auto?\s?/i;
26619 var autoPlace = autoToken.test(placement);
26621 placement = placement.replace(autoToken, '') || 'top';
26625 //this.el.setXY([0,0]);
26627 //this.el.dom.style.display='block';
26629 //this.el.appendTo(on_el);
26631 var p = this.getPosition();
26632 var box = this.el.getBox();
26638 var align = this.alignment[placement];
26640 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26642 if(placement == 'top' || placement == 'bottom'){
26644 placement = 'right';
26647 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26648 placement = 'left';
26651 var scroll = Roo.select('body', true).first().getScroll();
26653 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26657 align = this.alignment[placement];
26660 this.el.alignTo(this.bindEl, align[0],align[1]);
26661 //var arrow = this.el.select('.arrow',true).first();
26662 //arrow.set(align[2],
26664 this.el.addClass(placement);
26666 this.el.addClass('in fade');
26668 this.hoverState = null;
26670 if (this.el.hasClass('fade')) {
26681 //this.el.setXY([0,0]);
26682 this.el.removeClass('in');
26698 * @class Roo.bootstrap.LocationPicker
26699 * @extends Roo.bootstrap.Component
26700 * Bootstrap LocationPicker class
26701 * @cfg {Number} latitude Position when init default 0
26702 * @cfg {Number} longitude Position when init default 0
26703 * @cfg {Number} zoom default 15
26704 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26705 * @cfg {Boolean} mapTypeControl default false
26706 * @cfg {Boolean} disableDoubleClickZoom default false
26707 * @cfg {Boolean} scrollwheel default true
26708 * @cfg {Boolean} streetViewControl default false
26709 * @cfg {Number} radius default 0
26710 * @cfg {String} locationName
26711 * @cfg {Boolean} draggable default true
26712 * @cfg {Boolean} enableAutocomplete default false
26713 * @cfg {Boolean} enableReverseGeocode default true
26714 * @cfg {String} markerTitle
26717 * Create a new LocationPicker
26718 * @param {Object} config The config object
26722 Roo.bootstrap.LocationPicker = function(config){
26724 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26729 * Fires when the picker initialized.
26730 * @param {Roo.bootstrap.LocationPicker} this
26731 * @param {Google Location} location
26735 * @event positionchanged
26736 * Fires when the picker position changed.
26737 * @param {Roo.bootstrap.LocationPicker} this
26738 * @param {Google Location} location
26740 positionchanged : true,
26743 * Fires when the map resize.
26744 * @param {Roo.bootstrap.LocationPicker} this
26749 * Fires when the map show.
26750 * @param {Roo.bootstrap.LocationPicker} this
26755 * Fires when the map hide.
26756 * @param {Roo.bootstrap.LocationPicker} this
26761 * Fires when click the map.
26762 * @param {Roo.bootstrap.LocationPicker} this
26763 * @param {Map event} e
26767 * @event mapRightClick
26768 * Fires when right click the map.
26769 * @param {Roo.bootstrap.LocationPicker} this
26770 * @param {Map event} e
26772 mapRightClick : true,
26774 * @event markerClick
26775 * Fires when click the marker.
26776 * @param {Roo.bootstrap.LocationPicker} this
26777 * @param {Map event} e
26779 markerClick : true,
26781 * @event markerRightClick
26782 * Fires when right click the marker.
26783 * @param {Roo.bootstrap.LocationPicker} this
26784 * @param {Map event} e
26786 markerRightClick : true,
26788 * @event OverlayViewDraw
26789 * Fires when OverlayView Draw
26790 * @param {Roo.bootstrap.LocationPicker} this
26792 OverlayViewDraw : true,
26794 * @event OverlayViewOnAdd
26795 * Fires when OverlayView Draw
26796 * @param {Roo.bootstrap.LocationPicker} this
26798 OverlayViewOnAdd : true,
26800 * @event OverlayViewOnRemove
26801 * Fires when OverlayView Draw
26802 * @param {Roo.bootstrap.LocationPicker} this
26804 OverlayViewOnRemove : true,
26806 * @event OverlayViewShow
26807 * Fires when OverlayView Draw
26808 * @param {Roo.bootstrap.LocationPicker} this
26809 * @param {Pixel} cpx
26811 OverlayViewShow : true,
26813 * @event OverlayViewHide
26814 * Fires when OverlayView Draw
26815 * @param {Roo.bootstrap.LocationPicker} this
26817 OverlayViewHide : true,
26819 * @event loadexception
26820 * Fires when load google lib failed.
26821 * @param {Roo.bootstrap.LocationPicker} this
26823 loadexception : true
26828 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26830 gMapContext: false,
26836 mapTypeControl: false,
26837 disableDoubleClickZoom: false,
26839 streetViewControl: false,
26843 enableAutocomplete: false,
26844 enableReverseGeocode: true,
26847 getAutoCreate: function()
26852 cls: 'roo-location-picker'
26858 initEvents: function(ct, position)
26860 if(!this.el.getWidth() || this.isApplied()){
26864 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26869 initial: function()
26871 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26872 this.fireEvent('loadexception', this);
26876 if(!this.mapTypeId){
26877 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26880 this.gMapContext = this.GMapContext();
26882 this.initOverlayView();
26884 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26888 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26889 _this.setPosition(_this.gMapContext.marker.position);
26892 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26893 _this.fireEvent('mapClick', this, event);
26897 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26898 _this.fireEvent('mapRightClick', this, event);
26902 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26903 _this.fireEvent('markerClick', this, event);
26907 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26908 _this.fireEvent('markerRightClick', this, event);
26912 this.setPosition(this.gMapContext.location);
26914 this.fireEvent('initial', this, this.gMapContext.location);
26917 initOverlayView: function()
26921 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26925 _this.fireEvent('OverlayViewDraw', _this);
26930 _this.fireEvent('OverlayViewOnAdd', _this);
26933 onRemove: function()
26935 _this.fireEvent('OverlayViewOnRemove', _this);
26938 show: function(cpx)
26940 _this.fireEvent('OverlayViewShow', _this, cpx);
26945 _this.fireEvent('OverlayViewHide', _this);
26951 fromLatLngToContainerPixel: function(event)
26953 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26956 isApplied: function()
26958 return this.getGmapContext() == false ? false : true;
26961 getGmapContext: function()
26963 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26966 GMapContext: function()
26968 var position = new google.maps.LatLng(this.latitude, this.longitude);
26970 var _map = new google.maps.Map(this.el.dom, {
26973 mapTypeId: this.mapTypeId,
26974 mapTypeControl: this.mapTypeControl,
26975 disableDoubleClickZoom: this.disableDoubleClickZoom,
26976 scrollwheel: this.scrollwheel,
26977 streetViewControl: this.streetViewControl,
26978 locationName: this.locationName,
26979 draggable: this.draggable,
26980 enableAutocomplete: this.enableAutocomplete,
26981 enableReverseGeocode: this.enableReverseGeocode
26984 var _marker = new google.maps.Marker({
26985 position: position,
26987 title: this.markerTitle,
26988 draggable: this.draggable
26995 location: position,
26996 radius: this.radius,
26997 locationName: this.locationName,
26998 addressComponents: {
26999 formatted_address: null,
27000 addressLine1: null,
27001 addressLine2: null,
27003 streetNumber: null,
27007 stateOrProvince: null
27010 domContainer: this.el.dom,
27011 geodecoder: new google.maps.Geocoder()
27015 drawCircle: function(center, radius, options)
27017 if (this.gMapContext.circle != null) {
27018 this.gMapContext.circle.setMap(null);
27022 options = Roo.apply({}, options, {
27023 strokeColor: "#0000FF",
27024 strokeOpacity: .35,
27026 fillColor: "#0000FF",
27030 options.map = this.gMapContext.map;
27031 options.radius = radius;
27032 options.center = center;
27033 this.gMapContext.circle = new google.maps.Circle(options);
27034 return this.gMapContext.circle;
27040 setPosition: function(location)
27042 this.gMapContext.location = location;
27043 this.gMapContext.marker.setPosition(location);
27044 this.gMapContext.map.panTo(location);
27045 this.drawCircle(location, this.gMapContext.radius, {});
27049 if (this.gMapContext.settings.enableReverseGeocode) {
27050 this.gMapContext.geodecoder.geocode({
27051 latLng: this.gMapContext.location
27052 }, function(results, status) {
27054 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27055 _this.gMapContext.locationName = results[0].formatted_address;
27056 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27058 _this.fireEvent('positionchanged', this, location);
27065 this.fireEvent('positionchanged', this, location);
27070 google.maps.event.trigger(this.gMapContext.map, "resize");
27072 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27074 this.fireEvent('resize', this);
27077 setPositionByLatLng: function(latitude, longitude)
27079 this.setPosition(new google.maps.LatLng(latitude, longitude));
27082 getCurrentPosition: function()
27085 latitude: this.gMapContext.location.lat(),
27086 longitude: this.gMapContext.location.lng()
27090 getAddressName: function()
27092 return this.gMapContext.locationName;
27095 getAddressComponents: function()
27097 return this.gMapContext.addressComponents;
27100 address_component_from_google_geocode: function(address_components)
27104 for (var i = 0; i < address_components.length; i++) {
27105 var component = address_components[i];
27106 if (component.types.indexOf("postal_code") >= 0) {
27107 result.postalCode = component.short_name;
27108 } else if (component.types.indexOf("street_number") >= 0) {
27109 result.streetNumber = component.short_name;
27110 } else if (component.types.indexOf("route") >= 0) {
27111 result.streetName = component.short_name;
27112 } else if (component.types.indexOf("neighborhood") >= 0) {
27113 result.city = component.short_name;
27114 } else if (component.types.indexOf("locality") >= 0) {
27115 result.city = component.short_name;
27116 } else if (component.types.indexOf("sublocality") >= 0) {
27117 result.district = component.short_name;
27118 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27119 result.stateOrProvince = component.short_name;
27120 } else if (component.types.indexOf("country") >= 0) {
27121 result.country = component.short_name;
27125 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27126 result.addressLine2 = "";
27130 setZoomLevel: function(zoom)
27132 this.gMapContext.map.setZoom(zoom);
27145 this.fireEvent('show', this);
27156 this.fireEvent('hide', this);
27161 Roo.apply(Roo.bootstrap.LocationPicker, {
27163 OverlayView : function(map, options)
27165 options = options || {};
27179 * @class Roo.bootstrap.Alert
27180 * @extends Roo.bootstrap.Component
27181 * Bootstrap Alert class
27182 * @cfg {String} title The title of alert
27183 * @cfg {String} html The content of alert
27184 * @cfg {String} weight ( success | info | warning | danger )
27185 * @cfg {String} faicon font-awesomeicon
27188 * Create a new alert
27189 * @param {Object} config The config object
27193 Roo.bootstrap.Alert = function(config){
27194 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27198 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27205 getAutoCreate : function()
27214 cls : 'roo-alert-icon'
27219 cls : 'roo-alert-title',
27224 cls : 'roo-alert-text',
27231 cfg.cn[0].cls += ' fa ' + this.faicon;
27235 cfg.cls += ' alert-' + this.weight;
27241 initEvents: function()
27243 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27246 setTitle : function(str)
27248 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27251 setText : function(str)
27253 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27256 setWeight : function(weight)
27259 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27262 this.weight = weight;
27264 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27267 setIcon : function(icon)
27270 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27273 this.faicon = icon;
27275 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27296 * @class Roo.bootstrap.UploadCropbox
27297 * @extends Roo.bootstrap.Component
27298 * Bootstrap UploadCropbox class
27299 * @cfg {String} emptyText show when image has been loaded
27300 * @cfg {String} rotateNotify show when image too small to rotate
27301 * @cfg {Number} errorTimeout default 3000
27302 * @cfg {Number} minWidth default 300
27303 * @cfg {Number} minHeight default 300
27304 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27305 * @cfg {Boolean} isDocument (true|false) default false
27306 * @cfg {String} url action url
27307 * @cfg {String} paramName default 'imageUpload'
27308 * @cfg {String} method default POST
27309 * @cfg {Boolean} loadMask (true|false) default true
27310 * @cfg {Boolean} loadingText default 'Loading...'
27313 * Create a new UploadCropbox
27314 * @param {Object} config The config object
27317 Roo.bootstrap.UploadCropbox = function(config){
27318 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27322 * @event beforeselectfile
27323 * Fire before select file
27324 * @param {Roo.bootstrap.UploadCropbox} this
27326 "beforeselectfile" : true,
27329 * Fire after initEvent
27330 * @param {Roo.bootstrap.UploadCropbox} this
27335 * Fire after initEvent
27336 * @param {Roo.bootstrap.UploadCropbox} this
27337 * @param {String} data
27342 * Fire when preparing the file data
27343 * @param {Roo.bootstrap.UploadCropbox} this
27344 * @param {Object} file
27349 * Fire when get exception
27350 * @param {Roo.bootstrap.UploadCropbox} this
27351 * @param {XMLHttpRequest} xhr
27353 "exception" : true,
27355 * @event beforeloadcanvas
27356 * Fire before load the canvas
27357 * @param {Roo.bootstrap.UploadCropbox} this
27358 * @param {String} src
27360 "beforeloadcanvas" : true,
27363 * Fire when trash image
27364 * @param {Roo.bootstrap.UploadCropbox} this
27369 * Fire when download the image
27370 * @param {Roo.bootstrap.UploadCropbox} this
27374 * @event footerbuttonclick
27375 * Fire when footerbuttonclick
27376 * @param {Roo.bootstrap.UploadCropbox} this
27377 * @param {String} type
27379 "footerbuttonclick" : true,
27383 * @param {Roo.bootstrap.UploadCropbox} this
27388 * Fire when rotate the image
27389 * @param {Roo.bootstrap.UploadCropbox} this
27390 * @param {String} pos
27395 * Fire when inspect the file
27396 * @param {Roo.bootstrap.UploadCropbox} this
27397 * @param {Object} file
27402 * Fire when xhr upload the file
27403 * @param {Roo.bootstrap.UploadCropbox} this
27404 * @param {Object} data
27409 * Fire when arrange the file data
27410 * @param {Roo.bootstrap.UploadCropbox} this
27411 * @param {Object} formData
27416 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27419 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27421 emptyText : 'Click to upload image',
27422 rotateNotify : 'Image is too small to rotate',
27423 errorTimeout : 3000,
27437 cropType : 'image/jpeg',
27439 canvasLoaded : false,
27440 isDocument : false,
27442 paramName : 'imageUpload',
27444 loadingText : 'Loading...',
27447 getAutoCreate : function()
27451 cls : 'roo-upload-cropbox',
27455 cls : 'roo-upload-cropbox-selector',
27460 cls : 'roo-upload-cropbox-body',
27461 style : 'cursor:pointer',
27465 cls : 'roo-upload-cropbox-preview'
27469 cls : 'roo-upload-cropbox-thumb'
27473 cls : 'roo-upload-cropbox-empty-notify',
27474 html : this.emptyText
27478 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27479 html : this.rotateNotify
27485 cls : 'roo-upload-cropbox-footer',
27488 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27498 onRender : function(ct, position)
27500 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27502 if (this.buttons.length) {
27504 Roo.each(this.buttons, function(bb) {
27506 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27508 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27514 this.maskEl = this.el;
27518 initEvents : function()
27520 this.urlAPI = (window.createObjectURL && window) ||
27521 (window.URL && URL.revokeObjectURL && URL) ||
27522 (window.webkitURL && webkitURL);
27524 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27525 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27527 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27528 this.selectorEl.hide();
27530 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27531 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27533 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27534 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27535 this.thumbEl.hide();
27537 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27538 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27540 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27541 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27542 this.errorEl.hide();
27544 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27545 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27546 this.footerEl.hide();
27548 this.setThumbBoxSize();
27554 this.fireEvent('initial', this);
27561 window.addEventListener("resize", function() { _this.resize(); } );
27563 this.bodyEl.on('click', this.beforeSelectFile, this);
27566 this.bodyEl.on('touchstart', this.onTouchStart, this);
27567 this.bodyEl.on('touchmove', this.onTouchMove, this);
27568 this.bodyEl.on('touchend', this.onTouchEnd, this);
27572 this.bodyEl.on('mousedown', this.onMouseDown, this);
27573 this.bodyEl.on('mousemove', this.onMouseMove, this);
27574 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27575 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27576 Roo.get(document).on('mouseup', this.onMouseUp, this);
27579 this.selectorEl.on('change', this.onFileSelected, this);
27585 this.baseScale = 1;
27587 this.baseRotate = 1;
27588 this.dragable = false;
27589 this.pinching = false;
27592 this.cropData = false;
27593 this.notifyEl.dom.innerHTML = this.emptyText;
27595 this.selectorEl.dom.value = '';
27599 resize : function()
27601 if(this.fireEvent('resize', this) != false){
27602 this.setThumbBoxPosition();
27603 this.setCanvasPosition();
27607 onFooterButtonClick : function(e, el, o, type)
27610 case 'rotate-left' :
27611 this.onRotateLeft(e);
27613 case 'rotate-right' :
27614 this.onRotateRight(e);
27617 this.beforeSelectFile(e);
27632 this.fireEvent('footerbuttonclick', this, type);
27635 beforeSelectFile : function(e)
27637 e.preventDefault();
27639 if(this.fireEvent('beforeselectfile', this) != false){
27640 this.selectorEl.dom.click();
27644 onFileSelected : function(e)
27646 e.preventDefault();
27648 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27652 var file = this.selectorEl.dom.files[0];
27654 if(this.fireEvent('inspect', this, file) != false){
27655 this.prepare(file);
27660 trash : function(e)
27662 this.fireEvent('trash', this);
27665 download : function(e)
27667 this.fireEvent('download', this);
27670 loadCanvas : function(src)
27672 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27676 this.imageEl = document.createElement('img');
27680 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27682 this.imageEl.src = src;
27686 onLoadCanvas : function()
27688 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27689 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27691 this.bodyEl.un('click', this.beforeSelectFile, this);
27693 this.notifyEl.hide();
27694 this.thumbEl.show();
27695 this.footerEl.show();
27697 this.baseRotateLevel();
27699 if(this.isDocument){
27700 this.setThumbBoxSize();
27703 this.setThumbBoxPosition();
27705 this.baseScaleLevel();
27711 this.canvasLoaded = true;
27714 this.maskEl.unmask();
27719 setCanvasPosition : function()
27721 if(!this.canvasEl){
27725 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27726 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27728 this.previewEl.setLeft(pw);
27729 this.previewEl.setTop(ph);
27733 onMouseDown : function(e)
27737 this.dragable = true;
27738 this.pinching = false;
27740 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27741 this.dragable = false;
27745 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27746 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27750 onMouseMove : function(e)
27754 if(!this.canvasLoaded){
27758 if (!this.dragable){
27762 var minX = Math.ceil(this.thumbEl.getLeft(true));
27763 var minY = Math.ceil(this.thumbEl.getTop(true));
27765 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27766 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27768 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27769 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27771 x = x - this.mouseX;
27772 y = y - this.mouseY;
27774 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27775 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27777 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27778 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27780 this.previewEl.setLeft(bgX);
27781 this.previewEl.setTop(bgY);
27783 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27784 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27787 onMouseUp : function(e)
27791 this.dragable = false;
27794 onMouseWheel : function(e)
27798 this.startScale = this.scale;
27800 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27802 if(!this.zoomable()){
27803 this.scale = this.startScale;
27812 zoomable : function()
27814 var minScale = this.thumbEl.getWidth() / this.minWidth;
27816 if(this.minWidth < this.minHeight){
27817 minScale = this.thumbEl.getHeight() / this.minHeight;
27820 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27821 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27825 (this.rotate == 0 || this.rotate == 180) &&
27827 width > this.imageEl.OriginWidth ||
27828 height > this.imageEl.OriginHeight ||
27829 (width < this.minWidth && height < this.minHeight)
27837 (this.rotate == 90 || this.rotate == 270) &&
27839 width > this.imageEl.OriginWidth ||
27840 height > this.imageEl.OriginHeight ||
27841 (width < this.minHeight && height < this.minWidth)
27848 !this.isDocument &&
27849 (this.rotate == 0 || this.rotate == 180) &&
27851 width < this.minWidth ||
27852 width > this.imageEl.OriginWidth ||
27853 height < this.minHeight ||
27854 height > this.imageEl.OriginHeight
27861 !this.isDocument &&
27862 (this.rotate == 90 || this.rotate == 270) &&
27864 width < this.minHeight ||
27865 width > this.imageEl.OriginWidth ||
27866 height < this.minWidth ||
27867 height > this.imageEl.OriginHeight
27877 onRotateLeft : function(e)
27879 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27881 var minScale = this.thumbEl.getWidth() / this.minWidth;
27883 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27884 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27886 this.startScale = this.scale;
27888 while (this.getScaleLevel() < minScale){
27890 this.scale = this.scale + 1;
27892 if(!this.zoomable()){
27897 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27898 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27903 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27910 this.scale = this.startScale;
27912 this.onRotateFail();
27917 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27919 if(this.isDocument){
27920 this.setThumbBoxSize();
27921 this.setThumbBoxPosition();
27922 this.setCanvasPosition();
27927 this.fireEvent('rotate', this, 'left');
27931 onRotateRight : function(e)
27933 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27935 var minScale = this.thumbEl.getWidth() / this.minWidth;
27937 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27938 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27940 this.startScale = this.scale;
27942 while (this.getScaleLevel() < minScale){
27944 this.scale = this.scale + 1;
27946 if(!this.zoomable()){
27951 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27952 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27957 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27964 this.scale = this.startScale;
27966 this.onRotateFail();
27971 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27973 if(this.isDocument){
27974 this.setThumbBoxSize();
27975 this.setThumbBoxPosition();
27976 this.setCanvasPosition();
27981 this.fireEvent('rotate', this, 'right');
27984 onRotateFail : function()
27986 this.errorEl.show(true);
27990 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27995 this.previewEl.dom.innerHTML = '';
27997 var canvasEl = document.createElement("canvas");
27999 var contextEl = canvasEl.getContext("2d");
28001 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28002 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28003 var center = this.imageEl.OriginWidth / 2;
28005 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28006 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28007 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28008 center = this.imageEl.OriginHeight / 2;
28011 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28013 contextEl.translate(center, center);
28014 contextEl.rotate(this.rotate * Math.PI / 180);
28016 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28018 this.canvasEl = document.createElement("canvas");
28020 this.contextEl = this.canvasEl.getContext("2d");
28022 switch (this.rotate) {
28025 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28026 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28028 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28033 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28034 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28036 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28037 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28041 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28046 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28047 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28049 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28050 this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28054 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28059 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28060 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28062 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28063 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28067 this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28074 this.previewEl.appendChild(this.canvasEl);
28076 this.setCanvasPosition();
28081 if(!this.canvasLoaded){
28085 var imageCanvas = document.createElement("canvas");
28087 var imageContext = imageCanvas.getContext("2d");
28089 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28090 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28092 var center = imageCanvas.width / 2;
28094 imageContext.translate(center, center);
28096 imageContext.rotate(this.rotate * Math.PI / 180);
28098 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28100 var canvas = document.createElement("canvas");
28102 var context = canvas.getContext("2d");
28104 canvas.width = this.minWidth;
28105 canvas.height = this.minHeight;
28107 switch (this.rotate) {
28110 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28111 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28113 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28114 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28116 var targetWidth = this.minWidth - 2 * x;
28117 var targetHeight = this.minHeight - 2 * y;
28121 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28122 scale = targetWidth / width;
28125 if(x > 0 && y == 0){
28126 scale = targetHeight / height;
28129 if(x > 0 && y > 0){
28130 scale = targetWidth / width;
28132 if(width < height){
28133 scale = targetHeight / height;
28137 context.scale(scale, scale);
28139 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28140 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28142 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28143 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28145 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28150 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28151 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28153 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28154 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28156 var targetWidth = this.minWidth - 2 * x;
28157 var targetHeight = this.minHeight - 2 * y;
28161 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28162 scale = targetWidth / width;
28165 if(x > 0 && y == 0){
28166 scale = targetHeight / height;
28169 if(x > 0 && y > 0){
28170 scale = targetWidth / width;
28172 if(width < height){
28173 scale = targetHeight / height;
28177 context.scale(scale, scale);
28179 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28180 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28182 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28183 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28185 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28187 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28192 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28193 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28195 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28196 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28198 var targetWidth = this.minWidth - 2 * x;
28199 var targetHeight = this.minHeight - 2 * y;
28203 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28204 scale = targetWidth / width;
28207 if(x > 0 && y == 0){
28208 scale = targetHeight / height;
28211 if(x > 0 && y > 0){
28212 scale = targetWidth / width;
28214 if(width < height){
28215 scale = targetHeight / height;
28219 context.scale(scale, scale);
28221 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28222 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28224 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28225 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28227 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28228 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28230 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28235 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28236 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28238 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28239 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28241 var targetWidth = this.minWidth - 2 * x;
28242 var targetHeight = this.minHeight - 2 * y;
28246 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28247 scale = targetWidth / width;
28250 if(x > 0 && y == 0){
28251 scale = targetHeight / height;
28254 if(x > 0 && y > 0){
28255 scale = targetWidth / width;
28257 if(width < height){
28258 scale = targetHeight / height;
28262 context.scale(scale, scale);
28264 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28265 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28267 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28268 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28270 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28272 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28279 this.cropData = canvas.toDataURL(this.cropType);
28281 if(this.fireEvent('crop', this, this.cropData) !== false){
28282 this.process(this.file, this.cropData);
28289 setThumbBoxSize : function()
28293 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28294 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28295 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28297 this.minWidth = width;
28298 this.minHeight = height;
28300 if(this.rotate == 90 || this.rotate == 270){
28301 this.minWidth = height;
28302 this.minHeight = width;
28307 width = Math.ceil(this.minWidth * height / this.minHeight);
28309 if(this.minWidth > this.minHeight){
28311 height = Math.ceil(this.minHeight * width / this.minWidth);
28314 this.thumbEl.setStyle({
28315 width : width + 'px',
28316 height : height + 'px'
28323 setThumbBoxPosition : function()
28325 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28326 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28328 this.thumbEl.setLeft(x);
28329 this.thumbEl.setTop(y);
28333 baseRotateLevel : function()
28335 this.baseRotate = 1;
28338 typeof(this.exif) != 'undefined' &&
28339 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28340 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28342 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28345 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28349 baseScaleLevel : function()
28353 if(this.isDocument){
28355 if(this.baseRotate == 6 || this.baseRotate == 8){
28357 height = this.thumbEl.getHeight();
28358 this.baseScale = height / this.imageEl.OriginWidth;
28360 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28361 width = this.thumbEl.getWidth();
28362 this.baseScale = width / this.imageEl.OriginHeight;
28368 height = this.thumbEl.getHeight();
28369 this.baseScale = height / this.imageEl.OriginHeight;
28371 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28372 width = this.thumbEl.getWidth();
28373 this.baseScale = width / this.imageEl.OriginWidth;
28379 if(this.baseRotate == 6 || this.baseRotate == 8){
28381 width = this.thumbEl.getHeight();
28382 this.baseScale = width / this.imageEl.OriginHeight;
28384 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28385 height = this.thumbEl.getWidth();
28386 this.baseScale = height / this.imageEl.OriginHeight;
28389 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28390 height = this.thumbEl.getWidth();
28391 this.baseScale = height / this.imageEl.OriginHeight;
28393 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28394 width = this.thumbEl.getHeight();
28395 this.baseScale = width / this.imageEl.OriginWidth;
28402 width = this.thumbEl.getWidth();
28403 this.baseScale = width / this.imageEl.OriginWidth;
28405 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28406 height = this.thumbEl.getHeight();
28407 this.baseScale = height / this.imageEl.OriginHeight;
28410 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28412 height = this.thumbEl.getHeight();
28413 this.baseScale = height / this.imageEl.OriginHeight;
28415 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28416 width = this.thumbEl.getWidth();
28417 this.baseScale = width / this.imageEl.OriginWidth;
28425 getScaleLevel : function()
28427 return this.baseScale * Math.pow(1.1, this.scale);
28430 onTouchStart : function(e)
28432 if(!this.canvasLoaded){
28433 this.beforeSelectFile(e);
28437 var touches = e.browserEvent.touches;
28443 if(touches.length == 1){
28444 this.onMouseDown(e);
28448 if(touches.length != 2){
28454 for(var i = 0, finger; finger = touches[i]; i++){
28455 coords.push(finger.pageX, finger.pageY);
28458 var x = Math.pow(coords[0] - coords[2], 2);
28459 var y = Math.pow(coords[1] - coords[3], 2);
28461 this.startDistance = Math.sqrt(x + y);
28463 this.startScale = this.scale;
28465 this.pinching = true;
28466 this.dragable = false;
28470 onTouchMove : function(e)
28472 if(!this.pinching && !this.dragable){
28476 var touches = e.browserEvent.touches;
28483 this.onMouseMove(e);
28489 for(var i = 0, finger; finger = touches[i]; i++){
28490 coords.push(finger.pageX, finger.pageY);
28493 var x = Math.pow(coords[0] - coords[2], 2);
28494 var y = Math.pow(coords[1] - coords[3], 2);
28496 this.endDistance = Math.sqrt(x + y);
28498 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28500 if(!this.zoomable()){
28501 this.scale = this.startScale;
28509 onTouchEnd : function(e)
28511 this.pinching = false;
28512 this.dragable = false;
28516 process : function(file, crop)
28519 this.maskEl.mask(this.loadingText);
28522 this.xhr = new XMLHttpRequest();
28524 file.xhr = this.xhr;
28526 this.xhr.open(this.method, this.url, true);
28529 "Accept": "application/json",
28530 "Cache-Control": "no-cache",
28531 "X-Requested-With": "XMLHttpRequest"
28534 for (var headerName in headers) {
28535 var headerValue = headers[headerName];
28537 this.xhr.setRequestHeader(headerName, headerValue);
28543 this.xhr.onload = function()
28545 _this.xhrOnLoad(_this.xhr);
28548 this.xhr.onerror = function()
28550 _this.xhrOnError(_this.xhr);
28553 var formData = new FormData();
28555 formData.append('returnHTML', 'NO');
28558 formData.append('crop', crop);
28561 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28562 formData.append(this.paramName, file, file.name);
28565 if(typeof(file.filename) != 'undefined'){
28566 formData.append('filename', file.filename);
28569 if(typeof(file.mimetype) != 'undefined'){
28570 formData.append('mimetype', file.mimetype);
28573 if(this.fireEvent('arrange', this, formData) != false){
28574 this.xhr.send(formData);
28578 xhrOnLoad : function(xhr)
28581 this.maskEl.unmask();
28584 if (xhr.readyState !== 4) {
28585 this.fireEvent('exception', this, xhr);
28589 var response = Roo.decode(xhr.responseText);
28591 if(!response.success){
28592 this.fireEvent('exception', this, xhr);
28596 var response = Roo.decode(xhr.responseText);
28598 this.fireEvent('upload', this, response);
28602 xhrOnError : function()
28605 this.maskEl.unmask();
28608 Roo.log('xhr on error');
28610 var response = Roo.decode(xhr.responseText);
28616 prepare : function(file)
28619 this.maskEl.mask(this.loadingText);
28625 if(typeof(file) === 'string'){
28626 this.loadCanvas(file);
28630 if(!file || !this.urlAPI){
28635 this.cropType = file.type;
28639 if(this.fireEvent('prepare', this, this.file) != false){
28641 var reader = new FileReader();
28643 reader.onload = function (e) {
28644 if (e.target.error) {
28645 Roo.log(e.target.error);
28649 var buffer = e.target.result,
28650 dataView = new DataView(buffer),
28652 maxOffset = dataView.byteLength - 4,
28656 if (dataView.getUint16(0) === 0xffd8) {
28657 while (offset < maxOffset) {
28658 markerBytes = dataView.getUint16(offset);
28660 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28661 markerLength = dataView.getUint16(offset + 2) + 2;
28662 if (offset + markerLength > dataView.byteLength) {
28663 Roo.log('Invalid meta data: Invalid segment size.');
28667 if(markerBytes == 0xffe1){
28668 _this.parseExifData(
28675 offset += markerLength;
28685 var url = _this.urlAPI.createObjectURL(_this.file);
28687 _this.loadCanvas(url);
28692 reader.readAsArrayBuffer(this.file);
28698 parseExifData : function(dataView, offset, length)
28700 var tiffOffset = offset + 10,
28704 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28705 // No Exif data, might be XMP data instead
28709 // Check for the ASCII code for "Exif" (0x45786966):
28710 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28711 // No Exif data, might be XMP data instead
28714 if (tiffOffset + 8 > dataView.byteLength) {
28715 Roo.log('Invalid Exif data: Invalid segment size.');
28718 // Check for the two null bytes:
28719 if (dataView.getUint16(offset + 8) !== 0x0000) {
28720 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28723 // Check the byte alignment:
28724 switch (dataView.getUint16(tiffOffset)) {
28726 littleEndian = true;
28729 littleEndian = false;
28732 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28735 // Check for the TIFF tag marker (0x002A):
28736 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28737 Roo.log('Invalid Exif data: Missing TIFF marker.');
28740 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28741 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28743 this.parseExifTags(
28746 tiffOffset + dirOffset,
28751 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28756 if (dirOffset + 6 > dataView.byteLength) {
28757 Roo.log('Invalid Exif data: Invalid directory offset.');
28760 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28761 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28762 if (dirEndOffset + 4 > dataView.byteLength) {
28763 Roo.log('Invalid Exif data: Invalid directory size.');
28766 for (i = 0; i < tagsNumber; i += 1) {
28770 dirOffset + 2 + 12 * i, // tag offset
28774 // Return the offset to the next directory:
28775 return dataView.getUint32(dirEndOffset, littleEndian);
28778 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28780 var tag = dataView.getUint16(offset, littleEndian);
28782 this.exif[tag] = this.getExifValue(
28786 dataView.getUint16(offset + 2, littleEndian), // tag type
28787 dataView.getUint32(offset + 4, littleEndian), // tag length
28792 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28794 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28803 Roo.log('Invalid Exif data: Invalid tag type.');
28807 tagSize = tagType.size * length;
28808 // Determine if the value is contained in the dataOffset bytes,
28809 // or if the value at the dataOffset is a pointer to the actual data:
28810 dataOffset = tagSize > 4 ?
28811 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28812 if (dataOffset + tagSize > dataView.byteLength) {
28813 Roo.log('Invalid Exif data: Invalid data offset.');
28816 if (length === 1) {
28817 return tagType.getValue(dataView, dataOffset, littleEndian);
28820 for (i = 0; i < length; i += 1) {
28821 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28824 if (tagType.ascii) {
28826 // Concatenate the chars:
28827 for (i = 0; i < values.length; i += 1) {
28829 // Ignore the terminating NULL byte(s):
28830 if (c === '\u0000') {
28842 Roo.apply(Roo.bootstrap.UploadCropbox, {
28844 'Orientation': 0x0112
28848 1: 0, //'top-left',
28850 3: 180, //'bottom-right',
28851 // 4: 'bottom-left',
28853 6: 90, //'right-top',
28854 // 7: 'right-bottom',
28855 8: 270 //'left-bottom'
28859 // byte, 8-bit unsigned int:
28861 getValue: function (dataView, dataOffset) {
28862 return dataView.getUint8(dataOffset);
28866 // ascii, 8-bit byte:
28868 getValue: function (dataView, dataOffset) {
28869 return String.fromCharCode(dataView.getUint8(dataOffset));
28874 // short, 16 bit int:
28876 getValue: function (dataView, dataOffset, littleEndian) {
28877 return dataView.getUint16(dataOffset, littleEndian);
28881 // long, 32 bit int:
28883 getValue: function (dataView, dataOffset, littleEndian) {
28884 return dataView.getUint32(dataOffset, littleEndian);
28888 // rational = two long values, first is numerator, second is denominator:
28890 getValue: function (dataView, dataOffset, littleEndian) {
28891 return dataView.getUint32(dataOffset, littleEndian) /
28892 dataView.getUint32(dataOffset + 4, littleEndian);
28896 // slong, 32 bit signed int:
28898 getValue: function (dataView, dataOffset, littleEndian) {
28899 return dataView.getInt32(dataOffset, littleEndian);
28903 // srational, two slongs, first is numerator, second is denominator:
28905 getValue: function (dataView, dataOffset, littleEndian) {
28906 return dataView.getInt32(dataOffset, littleEndian) /
28907 dataView.getInt32(dataOffset + 4, littleEndian);
28917 cls : 'btn-group roo-upload-cropbox-rotate-left',
28918 action : 'rotate-left',
28922 cls : 'btn btn-default',
28923 html : '<i class="fa fa-undo"></i>'
28929 cls : 'btn-group roo-upload-cropbox-picture',
28930 action : 'picture',
28934 cls : 'btn btn-default',
28935 html : '<i class="fa fa-picture-o"></i>'
28941 cls : 'btn-group roo-upload-cropbox-rotate-right',
28942 action : 'rotate-right',
28946 cls : 'btn btn-default',
28947 html : '<i class="fa fa-repeat"></i>'
28955 cls : 'btn-group roo-upload-cropbox-rotate-left',
28956 action : 'rotate-left',
28960 cls : 'btn btn-default',
28961 html : '<i class="fa fa-undo"></i>'
28967 cls : 'btn-group roo-upload-cropbox-download',
28968 action : 'download',
28972 cls : 'btn btn-default',
28973 html : '<i class="fa fa-download"></i>'
28979 cls : 'btn-group roo-upload-cropbox-crop',
28984 cls : 'btn btn-default',
28985 html : '<i class="fa fa-crop"></i>'
28991 cls : 'btn-group roo-upload-cropbox-trash',
28996 cls : 'btn btn-default',
28997 html : '<i class="fa fa-trash"></i>'
29003 cls : 'btn-group roo-upload-cropbox-rotate-right',
29004 action : 'rotate-right',
29008 cls : 'btn btn-default',
29009 html : '<i class="fa fa-repeat"></i>'
29017 cls : 'btn-group roo-upload-cropbox-rotate-left',
29018 action : 'rotate-left',
29022 cls : 'btn btn-default',
29023 html : '<i class="fa fa-undo"></i>'
29029 cls : 'btn-group roo-upload-cropbox-rotate-right',
29030 action : 'rotate-right',
29034 cls : 'btn btn-default',
29035 html : '<i class="fa fa-repeat"></i>'
29048 * @class Roo.bootstrap.DocumentManager
29049 * @extends Roo.bootstrap.Component
29050 * Bootstrap DocumentManager class
29051 * @cfg {String} paramName default 'imageUpload'
29052 * @cfg {String} toolTipName default 'filename'
29053 * @cfg {String} method default POST
29054 * @cfg {String} url action url
29055 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29056 * @cfg {Boolean} multiple multiple upload default true
29057 * @cfg {Number} thumbSize default 300
29058 * @cfg {String} fieldLabel
29059 * @cfg {Number} labelWidth default 4
29060 * @cfg {String} labelAlign (left|top) default left
29061 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29062 * @cfg {Number} labellg set the width of label (1-12)
29063 * @cfg {Number} labelmd set the width of label (1-12)
29064 * @cfg {Number} labelsm set the width of label (1-12)
29065 * @cfg {Number} labelxs set the width of label (1-12)
29068 * Create a new DocumentManager
29069 * @param {Object} config The config object
29072 Roo.bootstrap.DocumentManager = function(config){
29073 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29076 this.delegates = [];
29081 * Fire when initial the DocumentManager
29082 * @param {Roo.bootstrap.DocumentManager} this
29087 * inspect selected file
29088 * @param {Roo.bootstrap.DocumentManager} this
29089 * @param {File} file
29094 * Fire when xhr load exception
29095 * @param {Roo.bootstrap.DocumentManager} this
29096 * @param {XMLHttpRequest} xhr
29098 "exception" : true,
29100 * @event afterupload
29101 * Fire when xhr load exception
29102 * @param {Roo.bootstrap.DocumentManager} this
29103 * @param {XMLHttpRequest} xhr
29105 "afterupload" : true,
29108 * prepare the form data
29109 * @param {Roo.bootstrap.DocumentManager} this
29110 * @param {Object} formData
29115 * Fire when remove the file
29116 * @param {Roo.bootstrap.DocumentManager} this
29117 * @param {Object} file
29122 * Fire after refresh the file
29123 * @param {Roo.bootstrap.DocumentManager} this
29128 * Fire after click the image
29129 * @param {Roo.bootstrap.DocumentManager} this
29130 * @param {Object} file
29135 * Fire when upload a image and editable set to true
29136 * @param {Roo.bootstrap.DocumentManager} this
29137 * @param {Object} file
29141 * @event beforeselectfile
29142 * Fire before select file
29143 * @param {Roo.bootstrap.DocumentManager} this
29145 "beforeselectfile" : true,
29148 * Fire before process file
29149 * @param {Roo.bootstrap.DocumentManager} this
29150 * @param {Object} file
29154 * @event previewrendered
29155 * Fire when preview rendered
29156 * @param {Roo.bootstrap.DocumentManager} this
29157 * @param {Object} file
29159 "previewrendered" : true,
29162 "previewResize" : true
29167 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29176 paramName : 'imageUpload',
29177 toolTipName : 'filename',
29180 labelAlign : 'left',
29190 getAutoCreate : function()
29192 var managerWidget = {
29194 cls : 'roo-document-manager',
29198 cls : 'roo-document-manager-selector',
29203 cls : 'roo-document-manager-uploader',
29207 cls : 'roo-document-manager-upload-btn',
29208 html : '<i class="fa fa-plus"></i>'
29219 cls : 'column col-md-12',
29224 if(this.fieldLabel.length){
29229 cls : 'column col-md-12',
29230 html : this.fieldLabel
29234 cls : 'column col-md-12',
29239 if(this.labelAlign == 'left'){
29244 html : this.fieldLabel
29253 if(this.labelWidth > 12){
29254 content[0].style = "width: " + this.labelWidth + 'px';
29257 if(this.labelWidth < 13 && this.labelmd == 0){
29258 this.labelmd = this.labelWidth;
29261 if(this.labellg > 0){
29262 content[0].cls += ' col-lg-' + this.labellg;
29263 content[1].cls += ' col-lg-' + (12 - this.labellg);
29266 if(this.labelmd > 0){
29267 content[0].cls += ' col-md-' + this.labelmd;
29268 content[1].cls += ' col-md-' + (12 - this.labelmd);
29271 if(this.labelsm > 0){
29272 content[0].cls += ' col-sm-' + this.labelsm;
29273 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29276 if(this.labelxs > 0){
29277 content[0].cls += ' col-xs-' + this.labelxs;
29278 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29286 cls : 'row clearfix',
29294 initEvents : function()
29296 this.managerEl = this.el.select('.roo-document-manager', true).first();
29297 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29299 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29300 this.selectorEl.hide();
29303 this.selectorEl.attr('multiple', 'multiple');
29306 this.selectorEl.on('change', this.onFileSelected, this);
29308 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29309 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29311 this.uploader.on('click', this.onUploaderClick, this);
29313 this.renderProgressDialog();
29317 window.addEventListener("resize", function() { _this.refresh(); } );
29319 this.fireEvent('initial', this);
29322 renderProgressDialog : function()
29326 this.progressDialog = new Roo.bootstrap.Modal({
29327 cls : 'roo-document-manager-progress-dialog',
29328 allow_close : false,
29339 btnclick : function() {
29340 _this.uploadCancel();
29346 this.progressDialog.render(Roo.get(document.body));
29348 this.progress = new Roo.bootstrap.Progress({
29349 cls : 'roo-document-manager-progress',
29354 this.progress.render(this.progressDialog.getChildContainer());
29356 this.progressBar = new Roo.bootstrap.ProgressBar({
29357 cls : 'roo-document-manager-progress-bar',
29360 aria_valuemax : 12,
29364 this.progressBar.render(this.progress.getChildContainer());
29367 onUploaderClick : function(e)
29369 e.preventDefault();
29371 if(this.fireEvent('beforeselectfile', this) != false){
29372 this.selectorEl.dom.click();
29377 onFileSelected : function(e)
29379 e.preventDefault();
29381 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29385 Roo.each(this.selectorEl.dom.files, function(file){
29386 if(this.fireEvent('inspect', this, file) != false){
29387 this.files.push(file);
29397 this.selectorEl.dom.value = '';
29399 if(!this.files || !this.files.length){
29403 if(this.boxes > 0 && this.files.length > this.boxes){
29404 this.files = this.files.slice(0, this.boxes);
29407 this.uploader.show();
29409 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29410 this.uploader.hide();
29419 Roo.each(this.files, function(file){
29421 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29422 var f = this.renderPreview(file);
29427 if(file.type.indexOf('image') != -1){
29428 this.delegates.push(
29430 _this.process(file);
29431 }).createDelegate(this)
29439 _this.process(file);
29440 }).createDelegate(this)
29445 this.files = files;
29447 this.delegates = this.delegates.concat(docs);
29449 if(!this.delegates.length){
29454 this.progressBar.aria_valuemax = this.delegates.length;
29461 arrange : function()
29463 if(!this.delegates.length){
29464 this.progressDialog.hide();
29469 var delegate = this.delegates.shift();
29471 this.progressDialog.show();
29473 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29475 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29480 refresh : function()
29482 this.uploader.show();
29484 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29485 this.uploader.hide();
29488 Roo.isTouch ? this.closable(false) : this.closable(true);
29490 this.fireEvent('refresh', this);
29493 onRemove : function(e, el, o)
29495 e.preventDefault();
29497 this.fireEvent('remove', this, o);
29501 remove : function(o)
29505 Roo.each(this.files, function(file){
29506 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29515 this.files = files;
29522 Roo.each(this.files, function(file){
29527 file.target.remove();
29536 onClick : function(e, el, o)
29538 e.preventDefault();
29540 this.fireEvent('click', this, o);
29544 closable : function(closable)
29546 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29548 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29560 xhrOnLoad : function(xhr)
29562 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29566 if (xhr.readyState !== 4) {
29568 this.fireEvent('exception', this, xhr);
29572 var response = Roo.decode(xhr.responseText);
29574 if(!response.success){
29576 this.fireEvent('exception', this, xhr);
29580 var file = this.renderPreview(response.data);
29582 this.files.push(file);
29586 this.fireEvent('afterupload', this, xhr);
29590 xhrOnError : function(xhr)
29592 Roo.log('xhr on error');
29594 var response = Roo.decode(xhr.responseText);
29601 process : function(file)
29603 if(this.fireEvent('process', this, file) !== false){
29604 if(this.editable && file.type.indexOf('image') != -1){
29605 this.fireEvent('edit', this, file);
29609 this.uploadStart(file, false);
29616 uploadStart : function(file, crop)
29618 this.xhr = new XMLHttpRequest();
29620 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29625 file.xhr = this.xhr;
29627 this.managerEl.createChild({
29629 cls : 'roo-document-manager-loading',
29633 tooltip : file.name,
29634 cls : 'roo-document-manager-thumb',
29635 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29641 this.xhr.open(this.method, this.url, true);
29644 "Accept": "application/json",
29645 "Cache-Control": "no-cache",
29646 "X-Requested-With": "XMLHttpRequest"
29649 for (var headerName in headers) {
29650 var headerValue = headers[headerName];
29652 this.xhr.setRequestHeader(headerName, headerValue);
29658 this.xhr.onload = function()
29660 _this.xhrOnLoad(_this.xhr);
29663 this.xhr.onerror = function()
29665 _this.xhrOnError(_this.xhr);
29668 var formData = new FormData();
29670 formData.append('returnHTML', 'NO');
29673 formData.append('crop', crop);
29676 formData.append(this.paramName, file, file.name);
29683 if(this.fireEvent('prepare', this, formData, options) != false){
29685 if(options.manually){
29689 this.xhr.send(formData);
29693 this.uploadCancel();
29696 uploadCancel : function()
29702 this.delegates = [];
29704 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29711 renderPreview : function(file)
29713 if(typeof(file.target) != 'undefined' && file.target){
29717 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29719 var previewEl = this.managerEl.createChild({
29721 cls : 'roo-document-manager-preview',
29725 tooltip : file[this.toolTipName],
29726 cls : 'roo-document-manager-thumb',
29727 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29732 html : '<i class="fa fa-times-circle"></i>'
29737 var close = previewEl.select('button.close', true).first();
29739 close.on('click', this.onRemove, this, file);
29741 file.target = previewEl;
29743 var image = previewEl.select('img', true).first();
29747 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29749 image.on('click', this.onClick, this, file);
29751 this.fireEvent('previewrendered', this, file);
29757 onPreviewLoad : function(file, image)
29759 if(typeof(file.target) == 'undefined' || !file.target){
29763 var width = image.dom.naturalWidth || image.dom.width;
29764 var height = image.dom.naturalHeight || image.dom.height;
29766 if(!this.previewResize) {
29770 if(width > height){
29771 file.target.addClass('wide');
29775 file.target.addClass('tall');
29780 uploadFromSource : function(file, crop)
29782 this.xhr = new XMLHttpRequest();
29784 this.managerEl.createChild({
29786 cls : 'roo-document-manager-loading',
29790 tooltip : file.name,
29791 cls : 'roo-document-manager-thumb',
29792 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29798 this.xhr.open(this.method, this.url, true);
29801 "Accept": "application/json",
29802 "Cache-Control": "no-cache",
29803 "X-Requested-With": "XMLHttpRequest"
29806 for (var headerName in headers) {
29807 var headerValue = headers[headerName];
29809 this.xhr.setRequestHeader(headerName, headerValue);
29815 this.xhr.onload = function()
29817 _this.xhrOnLoad(_this.xhr);
29820 this.xhr.onerror = function()
29822 _this.xhrOnError(_this.xhr);
29825 var formData = new FormData();
29827 formData.append('returnHTML', 'NO');
29829 formData.append('crop', crop);
29831 if(typeof(file.filename) != 'undefined'){
29832 formData.append('filename', file.filename);
29835 if(typeof(file.mimetype) != 'undefined'){
29836 formData.append('mimetype', file.mimetype);
29841 if(this.fireEvent('prepare', this, formData) != false){
29842 this.xhr.send(formData);
29852 * @class Roo.bootstrap.DocumentViewer
29853 * @extends Roo.bootstrap.Component
29854 * Bootstrap DocumentViewer class
29855 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29856 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29859 * Create a new DocumentViewer
29860 * @param {Object} config The config object
29863 Roo.bootstrap.DocumentViewer = function(config){
29864 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29869 * Fire after initEvent
29870 * @param {Roo.bootstrap.DocumentViewer} this
29876 * @param {Roo.bootstrap.DocumentViewer} this
29881 * Fire after download button
29882 * @param {Roo.bootstrap.DocumentViewer} this
29887 * Fire after trash button
29888 * @param {Roo.bootstrap.DocumentViewer} this
29895 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29897 showDownload : true,
29901 getAutoCreate : function()
29905 cls : 'roo-document-viewer',
29909 cls : 'roo-document-viewer-body',
29913 cls : 'roo-document-viewer-thumb',
29917 cls : 'roo-document-viewer-image'
29925 cls : 'roo-document-viewer-footer',
29928 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29932 cls : 'btn-group roo-document-viewer-download',
29936 cls : 'btn btn-default',
29937 html : '<i class="fa fa-download"></i>'
29943 cls : 'btn-group roo-document-viewer-trash',
29947 cls : 'btn btn-default',
29948 html : '<i class="fa fa-trash"></i>'
29961 initEvents : function()
29963 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29964 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29966 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29967 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29969 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29970 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29972 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29973 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29975 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29976 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29978 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29979 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29981 this.bodyEl.on('click', this.onClick, this);
29982 this.downloadBtn.on('click', this.onDownload, this);
29983 this.trashBtn.on('click', this.onTrash, this);
29985 this.downloadBtn.hide();
29986 this.trashBtn.hide();
29988 if(this.showDownload){
29989 this.downloadBtn.show();
29992 if(this.showTrash){
29993 this.trashBtn.show();
29996 if(!this.showDownload && !this.showTrash) {
29997 this.footerEl.hide();
30002 initial : function()
30004 this.fireEvent('initial', this);
30008 onClick : function(e)
30010 e.preventDefault();
30012 this.fireEvent('click', this);
30015 onDownload : function(e)
30017 e.preventDefault();
30019 this.fireEvent('download', this);
30022 onTrash : function(e)
30024 e.preventDefault();
30026 this.fireEvent('trash', this);
30038 * @class Roo.bootstrap.NavProgressBar
30039 * @extends Roo.bootstrap.Component
30040 * Bootstrap NavProgressBar class
30043 * Create a new nav progress bar
30044 * @param {Object} config The config object
30047 Roo.bootstrap.NavProgressBar = function(config){
30048 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30050 this.bullets = this.bullets || [];
30052 // Roo.bootstrap.NavProgressBar.register(this);
30056 * Fires when the active item changes
30057 * @param {Roo.bootstrap.NavProgressBar} this
30058 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30059 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30066 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30071 getAutoCreate : function()
30073 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30077 cls : 'roo-navigation-bar-group',
30081 cls : 'roo-navigation-top-bar'
30085 cls : 'roo-navigation-bullets-bar',
30089 cls : 'roo-navigation-bar'
30096 cls : 'roo-navigation-bottom-bar'
30106 initEvents: function()
30111 onRender : function(ct, position)
30113 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30115 if(this.bullets.length){
30116 Roo.each(this.bullets, function(b){
30125 addItem : function(cfg)
30127 var item = new Roo.bootstrap.NavProgressItem(cfg);
30129 item.parentId = this.id;
30130 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30133 var top = new Roo.bootstrap.Element({
30135 cls : 'roo-navigation-bar-text'
30138 var bottom = new Roo.bootstrap.Element({
30140 cls : 'roo-navigation-bar-text'
30143 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30144 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30146 var topText = new Roo.bootstrap.Element({
30148 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30151 var bottomText = new Roo.bootstrap.Element({
30153 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30156 topText.onRender(top.el, null);
30157 bottomText.onRender(bottom.el, null);
30160 item.bottomEl = bottom;
30163 this.barItems.push(item);
30168 getActive : function()
30170 var active = false;
30172 Roo.each(this.barItems, function(v){
30174 if (!v.isActive()) {
30186 setActiveItem : function(item)
30190 Roo.each(this.barItems, function(v){
30191 if (v.rid == item.rid) {
30195 if (v.isActive()) {
30196 v.setActive(false);
30201 item.setActive(true);
30203 this.fireEvent('changed', this, item, prev);
30206 getBarItem: function(rid)
30210 Roo.each(this.barItems, function(e) {
30211 if (e.rid != rid) {
30222 indexOfItem : function(item)
30226 Roo.each(this.barItems, function(v, i){
30228 if (v.rid != item.rid) {
30239 setActiveNext : function()
30241 var i = this.indexOfItem(this.getActive());
30243 if (i > this.barItems.length) {
30247 this.setActiveItem(this.barItems[i+1]);
30250 setActivePrev : function()
30252 var i = this.indexOfItem(this.getActive());
30258 this.setActiveItem(this.barItems[i-1]);
30261 format : function()
30263 if(!this.barItems.length){
30267 var width = 100 / this.barItems.length;
30269 Roo.each(this.barItems, function(i){
30270 i.el.setStyle('width', width + '%');
30271 i.topEl.el.setStyle('width', width + '%');
30272 i.bottomEl.el.setStyle('width', width + '%');
30281 * Nav Progress Item
30286 * @class Roo.bootstrap.NavProgressItem
30287 * @extends Roo.bootstrap.Component
30288 * Bootstrap NavProgressItem class
30289 * @cfg {String} rid the reference id
30290 * @cfg {Boolean} active (true|false) Is item active default false
30291 * @cfg {Boolean} disabled (true|false) Is item active default false
30292 * @cfg {String} html
30293 * @cfg {String} position (top|bottom) text position default bottom
30294 * @cfg {String} icon show icon instead of number
30297 * Create a new NavProgressItem
30298 * @param {Object} config The config object
30300 Roo.bootstrap.NavProgressItem = function(config){
30301 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30306 * The raw click event for the entire grid.
30307 * @param {Roo.bootstrap.NavProgressItem} this
30308 * @param {Roo.EventObject} e
30315 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30321 position : 'bottom',
30324 getAutoCreate : function()
30326 var iconCls = 'roo-navigation-bar-item-icon';
30328 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30332 cls: 'roo-navigation-bar-item',
30342 cfg.cls += ' active';
30345 cfg.cls += ' disabled';
30351 disable : function()
30353 this.setDisabled(true);
30356 enable : function()
30358 this.setDisabled(false);
30361 initEvents: function()
30363 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30365 this.iconEl.on('click', this.onClick, this);
30368 onClick : function(e)
30370 e.preventDefault();
30376 if(this.fireEvent('click', this, e) === false){
30380 this.parent().setActiveItem(this);
30383 isActive: function ()
30385 return this.active;
30388 setActive : function(state)
30390 if(this.active == state){
30394 this.active = state;
30397 this.el.addClass('active');
30401 this.el.removeClass('active');
30406 setDisabled : function(state)
30408 if(this.disabled == state){
30412 this.disabled = state;
30415 this.el.addClass('disabled');
30419 this.el.removeClass('disabled');
30422 tooltipEl : function()
30424 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30437 * @class Roo.bootstrap.FieldLabel
30438 * @extends Roo.bootstrap.Component
30439 * Bootstrap FieldLabel class
30440 * @cfg {String} html contents of the element
30441 * @cfg {String} tag tag of the element default label
30442 * @cfg {String} cls class of the element
30443 * @cfg {String} target label target
30444 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30445 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30446 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30447 * @cfg {String} iconTooltip default "This field is required"
30448 * @cfg {String} indicatorpos (left|right) default left
30451 * Create a new FieldLabel
30452 * @param {Object} config The config object
30455 Roo.bootstrap.FieldLabel = function(config){
30456 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30461 * Fires after the field has been marked as invalid.
30462 * @param {Roo.form.FieldLabel} this
30463 * @param {String} msg The validation message
30468 * Fires after the field has been validated with no errors.
30469 * @param {Roo.form.FieldLabel} this
30475 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30482 invalidClass : 'has-warning',
30483 validClass : 'has-success',
30484 iconTooltip : 'This field is required',
30485 indicatorpos : 'left',
30487 getAutoCreate : function(){
30490 if (!this.allowBlank) {
30496 cls : 'roo-bootstrap-field-label ' + this.cls,
30501 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30502 tooltip : this.iconTooltip
30511 if(this.indicatorpos == 'right'){
30514 cls : 'roo-bootstrap-field-label ' + this.cls,
30523 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30524 tooltip : this.iconTooltip
30533 initEvents: function()
30535 Roo.bootstrap.Element.superclass.initEvents.call(this);
30537 this.indicator = this.indicatorEl();
30539 if(this.indicator){
30540 this.indicator.removeClass('visible');
30541 this.indicator.addClass('invisible');
30544 Roo.bootstrap.FieldLabel.register(this);
30547 indicatorEl : function()
30549 var indicator = this.el.select('i.roo-required-indicator',true).first();
30560 * Mark this field as valid
30562 markValid : function()
30564 if(this.indicator){
30565 this.indicator.removeClass('visible');
30566 this.indicator.addClass('invisible');
30568 if (Roo.bootstrap.version == 3) {
30569 this.el.removeClass(this.invalidClass);
30570 this.el.addClass(this.validClass);
30572 this.el.removeClass('is-invalid');
30573 this.el.addClass('is-valid');
30577 this.fireEvent('valid', this);
30581 * Mark this field as invalid
30582 * @param {String} msg The validation message
30584 markInvalid : function(msg)
30586 if(this.indicator){
30587 this.indicator.removeClass('invisible');
30588 this.indicator.addClass('visible');
30590 if (Roo.bootstrap.version == 3) {
30591 this.el.removeClass(this.validClass);
30592 this.el.addClass(this.invalidClass);
30594 this.el.removeClass('is-valid');
30595 this.el.addClass('is-invalid');
30599 this.fireEvent('invalid', this, msg);
30605 Roo.apply(Roo.bootstrap.FieldLabel, {
30610 * register a FieldLabel Group
30611 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30613 register : function(label)
30615 if(this.groups.hasOwnProperty(label.target)){
30619 this.groups[label.target] = label;
30623 * fetch a FieldLabel Group based on the target
30624 * @param {string} target
30625 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30627 get: function(target) {
30628 if (typeof(this.groups[target]) == 'undefined') {
30632 return this.groups[target] ;
30641 * page DateSplitField.
30647 * @class Roo.bootstrap.DateSplitField
30648 * @extends Roo.bootstrap.Component
30649 * Bootstrap DateSplitField class
30650 * @cfg {string} fieldLabel - the label associated
30651 * @cfg {Number} labelWidth set the width of label (0-12)
30652 * @cfg {String} labelAlign (top|left)
30653 * @cfg {Boolean} dayAllowBlank (true|false) default false
30654 * @cfg {Boolean} monthAllowBlank (true|false) default false
30655 * @cfg {Boolean} yearAllowBlank (true|false) default false
30656 * @cfg {string} dayPlaceholder
30657 * @cfg {string} monthPlaceholder
30658 * @cfg {string} yearPlaceholder
30659 * @cfg {string} dayFormat default 'd'
30660 * @cfg {string} monthFormat default 'm'
30661 * @cfg {string} yearFormat default 'Y'
30662 * @cfg {Number} labellg set the width of label (1-12)
30663 * @cfg {Number} labelmd set the width of label (1-12)
30664 * @cfg {Number} labelsm set the width of label (1-12)
30665 * @cfg {Number} labelxs set the width of label (1-12)
30669 * Create a new DateSplitField
30670 * @param {Object} config The config object
30673 Roo.bootstrap.DateSplitField = function(config){
30674 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30680 * getting the data of years
30681 * @param {Roo.bootstrap.DateSplitField} this
30682 * @param {Object} years
30687 * getting the data of days
30688 * @param {Roo.bootstrap.DateSplitField} this
30689 * @param {Object} days
30694 * Fires after the field has been marked as invalid.
30695 * @param {Roo.form.Field} this
30696 * @param {String} msg The validation message
30701 * Fires after the field has been validated with no errors.
30702 * @param {Roo.form.Field} this
30708 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30711 labelAlign : 'top',
30713 dayAllowBlank : false,
30714 monthAllowBlank : false,
30715 yearAllowBlank : false,
30716 dayPlaceholder : '',
30717 monthPlaceholder : '',
30718 yearPlaceholder : '',
30722 isFormField : true,
30728 getAutoCreate : function()
30732 cls : 'row roo-date-split-field-group',
30737 cls : 'form-hidden-field roo-date-split-field-group-value',
30743 var labelCls = 'col-md-12';
30744 var contentCls = 'col-md-4';
30746 if(this.fieldLabel){
30750 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30754 html : this.fieldLabel
30759 if(this.labelAlign == 'left'){
30761 if(this.labelWidth > 12){
30762 label.style = "width: " + this.labelWidth + 'px';
30765 if(this.labelWidth < 13 && this.labelmd == 0){
30766 this.labelmd = this.labelWidth;
30769 if(this.labellg > 0){
30770 labelCls = ' col-lg-' + this.labellg;
30771 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30774 if(this.labelmd > 0){
30775 labelCls = ' col-md-' + this.labelmd;
30776 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30779 if(this.labelsm > 0){
30780 labelCls = ' col-sm-' + this.labelsm;
30781 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30784 if(this.labelxs > 0){
30785 labelCls = ' col-xs-' + this.labelxs;
30786 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30790 label.cls += ' ' + labelCls;
30792 cfg.cn.push(label);
30795 Roo.each(['day', 'month', 'year'], function(t){
30798 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30805 inputEl: function ()
30807 return this.el.select('.roo-date-split-field-group-value', true).first();
30810 onRender : function(ct, position)
30814 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30816 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30818 this.dayField = new Roo.bootstrap.ComboBox({
30819 allowBlank : this.dayAllowBlank,
30820 alwaysQuery : true,
30821 displayField : 'value',
30824 forceSelection : true,
30826 placeholder : this.dayPlaceholder,
30827 selectOnFocus : true,
30828 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30829 triggerAction : 'all',
30831 valueField : 'value',
30832 store : new Roo.data.SimpleStore({
30833 data : (function() {
30835 _this.fireEvent('days', _this, days);
30838 fields : [ 'value' ]
30841 select : function (_self, record, index)
30843 _this.setValue(_this.getValue());
30848 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30850 this.monthField = new Roo.bootstrap.MonthField({
30851 after : '<i class=\"fa fa-calendar\"></i>',
30852 allowBlank : this.monthAllowBlank,
30853 placeholder : this.monthPlaceholder,
30856 render : function (_self)
30858 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30859 e.preventDefault();
30863 select : function (_self, oldvalue, newvalue)
30865 _this.setValue(_this.getValue());
30870 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30872 this.yearField = new Roo.bootstrap.ComboBox({
30873 allowBlank : this.yearAllowBlank,
30874 alwaysQuery : true,
30875 displayField : 'value',
30878 forceSelection : true,
30880 placeholder : this.yearPlaceholder,
30881 selectOnFocus : true,
30882 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30883 triggerAction : 'all',
30885 valueField : 'value',
30886 store : new Roo.data.SimpleStore({
30887 data : (function() {
30889 _this.fireEvent('years', _this, years);
30892 fields : [ 'value' ]
30895 select : function (_self, record, index)
30897 _this.setValue(_this.getValue());
30902 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30905 setValue : function(v, format)
30907 this.inputEl.dom.value = v;
30909 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30911 var d = Date.parseDate(v, f);
30918 this.setDay(d.format(this.dayFormat));
30919 this.setMonth(d.format(this.monthFormat));
30920 this.setYear(d.format(this.yearFormat));
30927 setDay : function(v)
30929 this.dayField.setValue(v);
30930 this.inputEl.dom.value = this.getValue();
30935 setMonth : function(v)
30937 this.monthField.setValue(v, true);
30938 this.inputEl.dom.value = this.getValue();
30943 setYear : function(v)
30945 this.yearField.setValue(v);
30946 this.inputEl.dom.value = this.getValue();
30951 getDay : function()
30953 return this.dayField.getValue();
30956 getMonth : function()
30958 return this.monthField.getValue();
30961 getYear : function()
30963 return this.yearField.getValue();
30966 getValue : function()
30968 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30970 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30980 this.inputEl.dom.value = '';
30985 validate : function()
30987 var d = this.dayField.validate();
30988 var m = this.monthField.validate();
30989 var y = this.yearField.validate();
30994 (!this.dayAllowBlank && !d) ||
30995 (!this.monthAllowBlank && !m) ||
30996 (!this.yearAllowBlank && !y)
31001 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31010 this.markInvalid();
31015 markValid : function()
31018 var label = this.el.select('label', true).first();
31019 var icon = this.el.select('i.fa-star', true).first();
31025 this.fireEvent('valid', this);
31029 * Mark this field as invalid
31030 * @param {String} msg The validation message
31032 markInvalid : function(msg)
31035 var label = this.el.select('label', true).first();
31036 var icon = this.el.select('i.fa-star', true).first();
31038 if(label && !icon){
31039 this.el.select('.roo-date-split-field-label', true).createChild({
31041 cls : 'text-danger fa fa-lg fa-star',
31042 tooltip : 'This field is required',
31043 style : 'margin-right:5px;'
31047 this.fireEvent('invalid', this, msg);
31050 clearInvalid : function()
31052 var label = this.el.select('label', true).first();
31053 var icon = this.el.select('i.fa-star', true).first();
31059 this.fireEvent('valid', this);
31062 getName: function()
31072 * http://masonry.desandro.com
31074 * The idea is to render all the bricks based on vertical width...
31076 * The original code extends 'outlayer' - we might need to use that....
31082 * @class Roo.bootstrap.LayoutMasonry
31083 * @extends Roo.bootstrap.Component
31084 * Bootstrap Layout Masonry class
31087 * Create a new Element
31088 * @param {Object} config The config object
31091 Roo.bootstrap.LayoutMasonry = function(config){
31093 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31097 Roo.bootstrap.LayoutMasonry.register(this);
31103 * Fire after layout the items
31104 * @param {Roo.bootstrap.LayoutMasonry} this
31105 * @param {Roo.EventObject} e
31112 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31115 * @cfg {Boolean} isLayoutInstant = no animation?
31117 isLayoutInstant : false, // needed?
31120 * @cfg {Number} boxWidth width of the columns
31125 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31130 * @cfg {Number} padWidth padding below box..
31135 * @cfg {Number} gutter gutter width..
31140 * @cfg {Number} maxCols maximum number of columns
31146 * @cfg {Boolean} isAutoInitial defalut true
31148 isAutoInitial : true,
31153 * @cfg {Boolean} isHorizontal defalut false
31155 isHorizontal : false,
31157 currentSize : null,
31163 bricks: null, //CompositeElement
31167 _isLayoutInited : false,
31169 // isAlternative : false, // only use for vertical layout...
31172 * @cfg {Number} alternativePadWidth padding below box..
31174 alternativePadWidth : 50,
31176 selectedBrick : [],
31178 getAutoCreate : function(){
31180 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31184 cls: 'blog-masonary-wrapper ' + this.cls,
31186 cls : 'mas-boxes masonary'
31193 getChildContainer: function( )
31195 if (this.boxesEl) {
31196 return this.boxesEl;
31199 this.boxesEl = this.el.select('.mas-boxes').first();
31201 return this.boxesEl;
31205 initEvents : function()
31209 if(this.isAutoInitial){
31210 Roo.log('hook children rendered');
31211 this.on('childrenrendered', function() {
31212 Roo.log('children rendered');
31218 initial : function()
31220 this.selectedBrick = [];
31222 this.currentSize = this.el.getBox(true);
31224 Roo.EventManager.onWindowResize(this.resize, this);
31226 if(!this.isAutoInitial){
31234 //this.layout.defer(500,this);
31238 resize : function()
31240 var cs = this.el.getBox(true);
31243 this.currentSize.width == cs.width &&
31244 this.currentSize.x == cs.x &&
31245 this.currentSize.height == cs.height &&
31246 this.currentSize.y == cs.y
31248 Roo.log("no change in with or X or Y");
31252 this.currentSize = cs;
31258 layout : function()
31260 this._resetLayout();
31262 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31264 this.layoutItems( isInstant );
31266 this._isLayoutInited = true;
31268 this.fireEvent('layout', this);
31272 _resetLayout : function()
31274 if(this.isHorizontal){
31275 this.horizontalMeasureColumns();
31279 this.verticalMeasureColumns();
31283 verticalMeasureColumns : function()
31285 this.getContainerWidth();
31287 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31288 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31292 var boxWidth = this.boxWidth + this.padWidth;
31294 if(this.containerWidth < this.boxWidth){
31295 boxWidth = this.containerWidth
31298 var containerWidth = this.containerWidth;
31300 var cols = Math.floor(containerWidth / boxWidth);
31302 this.cols = Math.max( cols, 1 );
31304 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31306 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31308 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31310 this.colWidth = boxWidth + avail - this.padWidth;
31312 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31313 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31316 horizontalMeasureColumns : function()
31318 this.getContainerWidth();
31320 var boxWidth = this.boxWidth;
31322 if(this.containerWidth < boxWidth){
31323 boxWidth = this.containerWidth;
31326 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31328 this.el.setHeight(boxWidth);
31332 getContainerWidth : function()
31334 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31337 layoutItems : function( isInstant )
31339 Roo.log(this.bricks);
31341 var items = Roo.apply([], this.bricks);
31343 if(this.isHorizontal){
31344 this._horizontalLayoutItems( items , isInstant );
31348 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31349 // this._verticalAlternativeLayoutItems( items , isInstant );
31353 this._verticalLayoutItems( items , isInstant );
31357 _verticalLayoutItems : function ( items , isInstant)
31359 if ( !items || !items.length ) {
31364 ['xs', 'xs', 'xs', 'tall'],
31365 ['xs', 'xs', 'tall'],
31366 ['xs', 'xs', 'sm'],
31367 ['xs', 'xs', 'xs'],
31373 ['sm', 'xs', 'xs'],
31377 ['tall', 'xs', 'xs', 'xs'],
31378 ['tall', 'xs', 'xs'],
31390 Roo.each(items, function(item, k){
31392 switch (item.size) {
31393 // these layouts take up a full box,
31404 boxes.push([item]);
31427 var filterPattern = function(box, length)
31435 var pattern = box.slice(0, length);
31439 Roo.each(pattern, function(i){
31440 format.push(i.size);
31443 Roo.each(standard, function(s){
31445 if(String(s) != String(format)){
31454 if(!match && length == 1){
31459 filterPattern(box, length - 1);
31463 queue.push(pattern);
31465 box = box.slice(length, box.length);
31467 filterPattern(box, 4);
31473 Roo.each(boxes, function(box, k){
31479 if(box.length == 1){
31484 filterPattern(box, 4);
31488 this._processVerticalLayoutQueue( queue, isInstant );
31492 // _verticalAlternativeLayoutItems : function( items , isInstant )
31494 // if ( !items || !items.length ) {
31498 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31502 _horizontalLayoutItems : function ( items , isInstant)
31504 if ( !items || !items.length || items.length < 3) {
31510 var eItems = items.slice(0, 3);
31512 items = items.slice(3, items.length);
31515 ['xs', 'xs', 'xs', 'wide'],
31516 ['xs', 'xs', 'wide'],
31517 ['xs', 'xs', 'sm'],
31518 ['xs', 'xs', 'xs'],
31524 ['sm', 'xs', 'xs'],
31528 ['wide', 'xs', 'xs', 'xs'],
31529 ['wide', 'xs', 'xs'],
31542 Roo.each(items, function(item, k){
31544 switch (item.size) {
31555 boxes.push([item]);
31579 var filterPattern = function(box, length)
31587 var pattern = box.slice(0, length);
31591 Roo.each(pattern, function(i){
31592 format.push(i.size);
31595 Roo.each(standard, function(s){
31597 if(String(s) != String(format)){
31606 if(!match && length == 1){
31611 filterPattern(box, length - 1);
31615 queue.push(pattern);
31617 box = box.slice(length, box.length);
31619 filterPattern(box, 4);
31625 Roo.each(boxes, function(box, k){
31631 if(box.length == 1){
31636 filterPattern(box, 4);
31643 var pos = this.el.getBox(true);
31647 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31649 var hit_end = false;
31651 Roo.each(queue, function(box){
31655 Roo.each(box, function(b){
31657 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31667 Roo.each(box, function(b){
31669 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31672 mx = Math.max(mx, b.x);
31676 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31680 Roo.each(box, function(b){
31682 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31696 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31699 /** Sets position of item in DOM
31700 * @param {Element} item
31701 * @param {Number} x - horizontal position
31702 * @param {Number} y - vertical position
31703 * @param {Boolean} isInstant - disables transitions
31705 _processVerticalLayoutQueue : function( queue, isInstant )
31707 var pos = this.el.getBox(true);
31712 for (var i = 0; i < this.cols; i++){
31716 Roo.each(queue, function(box, k){
31718 var col = k % this.cols;
31720 Roo.each(box, function(b,kk){
31722 b.el.position('absolute');
31724 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31725 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31727 if(b.size == 'md-left' || b.size == 'md-right'){
31728 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31729 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31732 b.el.setWidth(width);
31733 b.el.setHeight(height);
31735 b.el.select('iframe',true).setSize(width,height);
31739 for (var i = 0; i < this.cols; i++){
31741 if(maxY[i] < maxY[col]){
31746 col = Math.min(col, i);
31750 x = pos.x + col * (this.colWidth + this.padWidth);
31754 var positions = [];
31756 switch (box.length){
31758 positions = this.getVerticalOneBoxColPositions(x, y, box);
31761 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31764 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31767 positions = this.getVerticalFourBoxColPositions(x, y, box);
31773 Roo.each(box, function(b,kk){
31775 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31777 var sz = b.el.getSize();
31779 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31787 for (var i = 0; i < this.cols; i++){
31788 mY = Math.max(mY, maxY[i]);
31791 this.el.setHeight(mY - pos.y);
31795 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31797 // var pos = this.el.getBox(true);
31800 // var maxX = pos.right;
31802 // var maxHeight = 0;
31804 // Roo.each(items, function(item, k){
31808 // item.el.position('absolute');
31810 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31812 // item.el.setWidth(width);
31814 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31816 // item.el.setHeight(height);
31819 // item.el.setXY([x, y], isInstant ? false : true);
31821 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31824 // y = y + height + this.alternativePadWidth;
31826 // maxHeight = maxHeight + height + this.alternativePadWidth;
31830 // this.el.setHeight(maxHeight);
31834 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31836 var pos = this.el.getBox(true);
31841 var maxX = pos.right;
31843 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31845 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31847 Roo.each(queue, function(box, k){
31849 Roo.each(box, function(b, kk){
31851 b.el.position('absolute');
31853 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31854 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31856 if(b.size == 'md-left' || b.size == 'md-right'){
31857 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31858 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31861 b.el.setWidth(width);
31862 b.el.setHeight(height);
31870 var positions = [];
31872 switch (box.length){
31874 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31877 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31880 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31883 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31889 Roo.each(box, function(b,kk){
31891 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31893 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31901 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31903 Roo.each(eItems, function(b,k){
31905 b.size = (k == 0) ? 'sm' : 'xs';
31906 b.x = (k == 0) ? 2 : 1;
31907 b.y = (k == 0) ? 2 : 1;
31909 b.el.position('absolute');
31911 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31913 b.el.setWidth(width);
31915 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31917 b.el.setHeight(height);
31921 var positions = [];
31924 x : maxX - this.unitWidth * 2 - this.gutter,
31929 x : maxX - this.unitWidth,
31930 y : minY + (this.unitWidth + this.gutter) * 2
31934 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31938 Roo.each(eItems, function(b,k){
31940 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31946 getVerticalOneBoxColPositions : function(x, y, box)
31950 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31952 if(box[0].size == 'md-left'){
31956 if(box[0].size == 'md-right'){
31961 x : x + (this.unitWidth + this.gutter) * rand,
31968 getVerticalTwoBoxColPositions : function(x, y, box)
31972 if(box[0].size == 'xs'){
31976 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31980 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31994 x : x + (this.unitWidth + this.gutter) * 2,
31995 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32002 getVerticalThreeBoxColPositions : function(x, y, box)
32006 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32014 x : x + (this.unitWidth + this.gutter) * 1,
32019 x : x + (this.unitWidth + this.gutter) * 2,
32027 if(box[0].size == 'xs' && box[1].size == 'xs'){
32036 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32040 x : x + (this.unitWidth + this.gutter) * 1,
32054 x : x + (this.unitWidth + this.gutter) * 2,
32059 x : x + (this.unitWidth + this.gutter) * 2,
32060 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32067 getVerticalFourBoxColPositions : function(x, y, box)
32071 if(box[0].size == 'xs'){
32080 y : y + (this.unitHeight + this.gutter) * 1
32085 y : y + (this.unitHeight + this.gutter) * 2
32089 x : x + (this.unitWidth + this.gutter) * 1,
32103 x : x + (this.unitWidth + this.gutter) * 2,
32108 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32109 y : y + (this.unitHeight + this.gutter) * 1
32113 x : x + (this.unitWidth + this.gutter) * 2,
32114 y : y + (this.unitWidth + this.gutter) * 2
32121 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32125 if(box[0].size == 'md-left'){
32127 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32134 if(box[0].size == 'md-right'){
32136 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32137 y : minY + (this.unitWidth + this.gutter) * 1
32143 var rand = Math.floor(Math.random() * (4 - box[0].y));
32146 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32147 y : minY + (this.unitWidth + this.gutter) * rand
32154 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32158 if(box[0].size == 'xs'){
32161 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32166 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32167 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32175 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32180 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32181 y : minY + (this.unitWidth + this.gutter) * 2
32188 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32192 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32195 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32200 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32201 y : minY + (this.unitWidth + this.gutter) * 1
32205 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32206 y : minY + (this.unitWidth + this.gutter) * 2
32213 if(box[0].size == 'xs' && box[1].size == 'xs'){
32216 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32221 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32226 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32227 y : minY + (this.unitWidth + this.gutter) * 1
32235 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32240 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32241 y : minY + (this.unitWidth + this.gutter) * 2
32245 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32246 y : minY + (this.unitWidth + this.gutter) * 2
32253 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32257 if(box[0].size == 'xs'){
32260 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32265 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32270 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32275 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32276 y : minY + (this.unitWidth + this.gutter) * 1
32284 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32289 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32290 y : minY + (this.unitWidth + this.gutter) * 2
32294 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32295 y : minY + (this.unitWidth + this.gutter) * 2
32299 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32300 y : minY + (this.unitWidth + this.gutter) * 2
32308 * remove a Masonry Brick
32309 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32311 removeBrick : function(brick_id)
32317 for (var i = 0; i<this.bricks.length; i++) {
32318 if (this.bricks[i].id == brick_id) {
32319 this.bricks.splice(i,1);
32320 this.el.dom.removeChild(Roo.get(brick_id).dom);
32327 * adds a Masonry Brick
32328 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32330 addBrick : function(cfg)
32332 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32333 //this.register(cn);
32334 cn.parentId = this.id;
32335 cn.render(this.el);
32340 * register a Masonry Brick
32341 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32344 register : function(brick)
32346 this.bricks.push(brick);
32347 brick.masonryId = this.id;
32351 * clear all the Masonry Brick
32353 clearAll : function()
32356 //this.getChildContainer().dom.innerHTML = "";
32357 this.el.dom.innerHTML = '';
32360 getSelected : function()
32362 if (!this.selectedBrick) {
32366 return this.selectedBrick;
32370 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32374 * register a Masonry Layout
32375 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32378 register : function(layout)
32380 this.groups[layout.id] = layout;
32383 * fetch a Masonry Layout based on the masonry layout ID
32384 * @param {string} the masonry layout to add
32385 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32388 get: function(layout_id) {
32389 if (typeof(this.groups[layout_id]) == 'undefined') {
32392 return this.groups[layout_id] ;
32404 * http://masonry.desandro.com
32406 * The idea is to render all the bricks based on vertical width...
32408 * The original code extends 'outlayer' - we might need to use that....
32414 * @class Roo.bootstrap.LayoutMasonryAuto
32415 * @extends Roo.bootstrap.Component
32416 * Bootstrap Layout Masonry class
32419 * Create a new Element
32420 * @param {Object} config The config object
32423 Roo.bootstrap.LayoutMasonryAuto = function(config){
32424 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32427 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32430 * @cfg {Boolean} isFitWidth - resize the width..
32432 isFitWidth : false, // options..
32434 * @cfg {Boolean} isOriginLeft = left align?
32436 isOriginLeft : true,
32438 * @cfg {Boolean} isOriginTop = top align?
32440 isOriginTop : false,
32442 * @cfg {Boolean} isLayoutInstant = no animation?
32444 isLayoutInstant : false, // needed?
32446 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32448 isResizingContainer : true,
32450 * @cfg {Number} columnWidth width of the columns
32456 * @cfg {Number} maxCols maximum number of columns
32461 * @cfg {Number} padHeight padding below box..
32467 * @cfg {Boolean} isAutoInitial defalut true
32470 isAutoInitial : true,
32476 initialColumnWidth : 0,
32477 currentSize : null,
32479 colYs : null, // array.
32486 bricks: null, //CompositeElement
32487 cols : 0, // array?
32488 // element : null, // wrapped now this.el
32489 _isLayoutInited : null,
32492 getAutoCreate : function(){
32496 cls: 'blog-masonary-wrapper ' + this.cls,
32498 cls : 'mas-boxes masonary'
32505 getChildContainer: function( )
32507 if (this.boxesEl) {
32508 return this.boxesEl;
32511 this.boxesEl = this.el.select('.mas-boxes').first();
32513 return this.boxesEl;
32517 initEvents : function()
32521 if(this.isAutoInitial){
32522 Roo.log('hook children rendered');
32523 this.on('childrenrendered', function() {
32524 Roo.log('children rendered');
32531 initial : function()
32533 this.reloadItems();
32535 this.currentSize = this.el.getBox(true);
32537 /// was window resize... - let's see if this works..
32538 Roo.EventManager.onWindowResize(this.resize, this);
32540 if(!this.isAutoInitial){
32545 this.layout.defer(500,this);
32548 reloadItems: function()
32550 this.bricks = this.el.select('.masonry-brick', true);
32552 this.bricks.each(function(b) {
32553 //Roo.log(b.getSize());
32554 if (!b.attr('originalwidth')) {
32555 b.attr('originalwidth', b.getSize().width);
32560 Roo.log(this.bricks.elements.length);
32563 resize : function()
32566 var cs = this.el.getBox(true);
32568 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32569 Roo.log("no change in with or X");
32572 this.currentSize = cs;
32576 layout : function()
32579 this._resetLayout();
32580 //this._manageStamps();
32582 // don't animate first layout
32583 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32584 this.layoutItems( isInstant );
32586 // flag for initalized
32587 this._isLayoutInited = true;
32590 layoutItems : function( isInstant )
32592 //var items = this._getItemsForLayout( this.items );
32593 // original code supports filtering layout items.. we just ignore it..
32595 this._layoutItems( this.bricks , isInstant );
32597 this._postLayout();
32599 _layoutItems : function ( items , isInstant)
32601 //this.fireEvent( 'layout', this, items );
32604 if ( !items || !items.elements.length ) {
32605 // no items, emit event with empty array
32610 items.each(function(item) {
32611 Roo.log("layout item");
32613 // get x/y object from method
32614 var position = this._getItemLayoutPosition( item );
32616 position.item = item;
32617 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32618 queue.push( position );
32621 this._processLayoutQueue( queue );
32623 /** Sets position of item in DOM
32624 * @param {Element} item
32625 * @param {Number} x - horizontal position
32626 * @param {Number} y - vertical position
32627 * @param {Boolean} isInstant - disables transitions
32629 _processLayoutQueue : function( queue )
32631 for ( var i=0, len = queue.length; i < len; i++ ) {
32632 var obj = queue[i];
32633 obj.item.position('absolute');
32634 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32640 * Any logic you want to do after each layout,
32641 * i.e. size the container
32643 _postLayout : function()
32645 this.resizeContainer();
32648 resizeContainer : function()
32650 if ( !this.isResizingContainer ) {
32653 var size = this._getContainerSize();
32655 this.el.setSize(size.width,size.height);
32656 this.boxesEl.setSize(size.width,size.height);
32662 _resetLayout : function()
32664 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32665 this.colWidth = this.el.getWidth();
32666 //this.gutter = this.el.getWidth();
32668 this.measureColumns();
32674 this.colYs.push( 0 );
32680 measureColumns : function()
32682 this.getContainerWidth();
32683 // if columnWidth is 0, default to outerWidth of first item
32684 if ( !this.columnWidth ) {
32685 var firstItem = this.bricks.first();
32686 Roo.log(firstItem);
32687 this.columnWidth = this.containerWidth;
32688 if (firstItem && firstItem.attr('originalwidth') ) {
32689 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32691 // columnWidth fall back to item of first element
32692 Roo.log("set column width?");
32693 this.initialColumnWidth = this.columnWidth ;
32695 // if first elem has no width, default to size of container
32700 if (this.initialColumnWidth) {
32701 this.columnWidth = this.initialColumnWidth;
32706 // column width is fixed at the top - however if container width get's smaller we should
32709 // this bit calcs how man columns..
32711 var columnWidth = this.columnWidth += this.gutter;
32713 // calculate columns
32714 var containerWidth = this.containerWidth + this.gutter;
32716 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32717 // fix rounding errors, typically with gutters
32718 var excess = columnWidth - containerWidth % columnWidth;
32721 // if overshoot is less than a pixel, round up, otherwise floor it
32722 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32723 cols = Math[ mathMethod ]( cols );
32724 this.cols = Math.max( cols, 1 );
32725 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32727 // padding positioning..
32728 var totalColWidth = this.cols * this.columnWidth;
32729 var padavail = this.containerWidth - totalColWidth;
32730 // so for 2 columns - we need 3 'pads'
32732 var padNeeded = (1+this.cols) * this.padWidth;
32734 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32736 this.columnWidth += padExtra
32737 //this.padWidth = Math.floor(padavail / ( this.cols));
32739 // adjust colum width so that padding is fixed??
32741 // we have 3 columns ... total = width * 3
32742 // we have X left over... that should be used by
32744 //if (this.expandC) {
32752 getContainerWidth : function()
32754 /* // container is parent if fit width
32755 var container = this.isFitWidth ? this.element.parentNode : this.element;
32756 // check that this.size and size are there
32757 // IE8 triggers resize on body size change, so they might not be
32759 var size = getSize( container ); //FIXME
32760 this.containerWidth = size && size.innerWidth; //FIXME
32763 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32767 _getItemLayoutPosition : function( item ) // what is item?
32769 // we resize the item to our columnWidth..
32771 item.setWidth(this.columnWidth);
32772 item.autoBoxAdjust = false;
32774 var sz = item.getSize();
32776 // how many columns does this brick span
32777 var remainder = this.containerWidth % this.columnWidth;
32779 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32780 // round if off by 1 pixel, otherwise use ceil
32781 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32782 colSpan = Math.min( colSpan, this.cols );
32784 // normally this should be '1' as we dont' currently allow multi width columns..
32786 var colGroup = this._getColGroup( colSpan );
32787 // get the minimum Y value from the columns
32788 var minimumY = Math.min.apply( Math, colGroup );
32789 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32791 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32793 // position the brick
32795 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32796 y: this.currentSize.y + minimumY + this.padHeight
32800 // apply setHeight to necessary columns
32801 var setHeight = minimumY + sz.height + this.padHeight;
32802 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32804 var setSpan = this.cols + 1 - colGroup.length;
32805 for ( var i = 0; i < setSpan; i++ ) {
32806 this.colYs[ shortColIndex + i ] = setHeight ;
32813 * @param {Number} colSpan - number of columns the element spans
32814 * @returns {Array} colGroup
32816 _getColGroup : function( colSpan )
32818 if ( colSpan < 2 ) {
32819 // if brick spans only one column, use all the column Ys
32824 // how many different places could this brick fit horizontally
32825 var groupCount = this.cols + 1 - colSpan;
32826 // for each group potential horizontal position
32827 for ( var i = 0; i < groupCount; i++ ) {
32828 // make an array of colY values for that one group
32829 var groupColYs = this.colYs.slice( i, i + colSpan );
32830 // and get the max value of the array
32831 colGroup[i] = Math.max.apply( Math, groupColYs );
32836 _manageStamp : function( stamp )
32838 var stampSize = stamp.getSize();
32839 var offset = stamp.getBox();
32840 // get the columns that this stamp affects
32841 var firstX = this.isOriginLeft ? offset.x : offset.right;
32842 var lastX = firstX + stampSize.width;
32843 var firstCol = Math.floor( firstX / this.columnWidth );
32844 firstCol = Math.max( 0, firstCol );
32846 var lastCol = Math.floor( lastX / this.columnWidth );
32847 // lastCol should not go over if multiple of columnWidth #425
32848 lastCol -= lastX % this.columnWidth ? 0 : 1;
32849 lastCol = Math.min( this.cols - 1, lastCol );
32851 // set colYs to bottom of the stamp
32852 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32855 for ( var i = firstCol; i <= lastCol; i++ ) {
32856 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32861 _getContainerSize : function()
32863 this.maxY = Math.max.apply( Math, this.colYs );
32868 if ( this.isFitWidth ) {
32869 size.width = this._getContainerFitWidth();
32875 _getContainerFitWidth : function()
32877 var unusedCols = 0;
32878 // count unused columns
32881 if ( this.colYs[i] !== 0 ) {
32886 // fit container to columns that have been used
32887 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32890 needsResizeLayout : function()
32892 var previousWidth = this.containerWidth;
32893 this.getContainerWidth();
32894 return previousWidth !== this.containerWidth;
32909 * @class Roo.bootstrap.MasonryBrick
32910 * @extends Roo.bootstrap.Component
32911 * Bootstrap MasonryBrick class
32914 * Create a new MasonryBrick
32915 * @param {Object} config The config object
32918 Roo.bootstrap.MasonryBrick = function(config){
32920 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32922 Roo.bootstrap.MasonryBrick.register(this);
32928 * When a MasonryBrick is clcik
32929 * @param {Roo.bootstrap.MasonryBrick} this
32930 * @param {Roo.EventObject} e
32936 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32939 * @cfg {String} title
32943 * @cfg {String} html
32947 * @cfg {String} bgimage
32951 * @cfg {String} videourl
32955 * @cfg {String} cls
32959 * @cfg {String} href
32963 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32968 * @cfg {String} placetitle (center|bottom)
32973 * @cfg {Boolean} isFitContainer defalut true
32975 isFitContainer : true,
32978 * @cfg {Boolean} preventDefault defalut false
32980 preventDefault : false,
32983 * @cfg {Boolean} inverse defalut false
32985 maskInverse : false,
32987 getAutoCreate : function()
32989 if(!this.isFitContainer){
32990 return this.getSplitAutoCreate();
32993 var cls = 'masonry-brick masonry-brick-full';
32995 if(this.href.length){
32996 cls += ' masonry-brick-link';
32999 if(this.bgimage.length){
33000 cls += ' masonry-brick-image';
33003 if(this.maskInverse){
33004 cls += ' mask-inverse';
33007 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33008 cls += ' enable-mask';
33012 cls += ' masonry-' + this.size + '-brick';
33015 if(this.placetitle.length){
33017 switch (this.placetitle) {
33019 cls += ' masonry-center-title';
33022 cls += ' masonry-bottom-title';
33029 if(!this.html.length && !this.bgimage.length){
33030 cls += ' masonry-center-title';
33033 if(!this.html.length && this.bgimage.length){
33034 cls += ' masonry-bottom-title';
33039 cls += ' ' + this.cls;
33043 tag: (this.href.length) ? 'a' : 'div',
33048 cls: 'masonry-brick-mask'
33052 cls: 'masonry-brick-paragraph',
33058 if(this.href.length){
33059 cfg.href = this.href;
33062 var cn = cfg.cn[1].cn;
33064 if(this.title.length){
33067 cls: 'masonry-brick-title',
33072 if(this.html.length){
33075 cls: 'masonry-brick-text',
33080 if (!this.title.length && !this.html.length) {
33081 cfg.cn[1].cls += ' hide';
33084 if(this.bgimage.length){
33087 cls: 'masonry-brick-image-view',
33092 if(this.videourl.length){
33093 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33094 // youtube support only?
33097 cls: 'masonry-brick-image-view',
33100 allowfullscreen : true
33108 getSplitAutoCreate : function()
33110 var cls = 'masonry-brick masonry-brick-split';
33112 if(this.href.length){
33113 cls += ' masonry-brick-link';
33116 if(this.bgimage.length){
33117 cls += ' masonry-brick-image';
33121 cls += ' masonry-' + this.size + '-brick';
33124 switch (this.placetitle) {
33126 cls += ' masonry-center-title';
33129 cls += ' masonry-bottom-title';
33132 if(!this.bgimage.length){
33133 cls += ' masonry-center-title';
33136 if(this.bgimage.length){
33137 cls += ' masonry-bottom-title';
33143 cls += ' ' + this.cls;
33147 tag: (this.href.length) ? 'a' : 'div',
33152 cls: 'masonry-brick-split-head',
33156 cls: 'masonry-brick-paragraph',
33163 cls: 'masonry-brick-split-body',
33169 if(this.href.length){
33170 cfg.href = this.href;
33173 if(this.title.length){
33174 cfg.cn[0].cn[0].cn.push({
33176 cls: 'masonry-brick-title',
33181 if(this.html.length){
33182 cfg.cn[1].cn.push({
33184 cls: 'masonry-brick-text',
33189 if(this.bgimage.length){
33190 cfg.cn[0].cn.push({
33192 cls: 'masonry-brick-image-view',
33197 if(this.videourl.length){
33198 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33199 // youtube support only?
33200 cfg.cn[0].cn.cn.push({
33202 cls: 'masonry-brick-image-view',
33205 allowfullscreen : true
33212 initEvents: function()
33214 switch (this.size) {
33247 this.el.on('touchstart', this.onTouchStart, this);
33248 this.el.on('touchmove', this.onTouchMove, this);
33249 this.el.on('touchend', this.onTouchEnd, this);
33250 this.el.on('contextmenu', this.onContextMenu, this);
33252 this.el.on('mouseenter' ,this.enter, this);
33253 this.el.on('mouseleave', this.leave, this);
33254 this.el.on('click', this.onClick, this);
33257 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33258 this.parent().bricks.push(this);
33263 onClick: function(e, el)
33265 var time = this.endTimer - this.startTimer;
33266 // Roo.log(e.preventDefault());
33269 e.preventDefault();
33274 if(!this.preventDefault){
33278 e.preventDefault();
33280 if (this.activeClass != '') {
33281 this.selectBrick();
33284 this.fireEvent('click', this, e);
33287 enter: function(e, el)
33289 e.preventDefault();
33291 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33295 if(this.bgimage.length && this.html.length){
33296 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33300 leave: function(e, el)
33302 e.preventDefault();
33304 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33308 if(this.bgimage.length && this.html.length){
33309 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33313 onTouchStart: function(e, el)
33315 // e.preventDefault();
33317 this.touchmoved = false;
33319 if(!this.isFitContainer){
33323 if(!this.bgimage.length || !this.html.length){
33327 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33329 this.timer = new Date().getTime();
33333 onTouchMove: function(e, el)
33335 this.touchmoved = true;
33338 onContextMenu : function(e,el)
33340 e.preventDefault();
33341 e.stopPropagation();
33345 onTouchEnd: function(e, el)
33347 // e.preventDefault();
33349 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33356 if(!this.bgimage.length || !this.html.length){
33358 if(this.href.length){
33359 window.location.href = this.href;
33365 if(!this.isFitContainer){
33369 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33371 window.location.href = this.href;
33374 //selection on single brick only
33375 selectBrick : function() {
33377 if (!this.parentId) {
33381 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33382 var index = m.selectedBrick.indexOf(this.id);
33385 m.selectedBrick.splice(index,1);
33386 this.el.removeClass(this.activeClass);
33390 for(var i = 0; i < m.selectedBrick.length; i++) {
33391 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33392 b.el.removeClass(b.activeClass);
33395 m.selectedBrick = [];
33397 m.selectedBrick.push(this.id);
33398 this.el.addClass(this.activeClass);
33402 isSelected : function(){
33403 return this.el.hasClass(this.activeClass);
33408 Roo.apply(Roo.bootstrap.MasonryBrick, {
33411 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33413 * register a Masonry Brick
33414 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33417 register : function(brick)
33419 //this.groups[brick.id] = brick;
33420 this.groups.add(brick.id, brick);
33423 * fetch a masonry brick based on the masonry brick ID
33424 * @param {string} the masonry brick to add
33425 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33428 get: function(brick_id)
33430 // if (typeof(this.groups[brick_id]) == 'undefined') {
33433 // return this.groups[brick_id] ;
33435 if(this.groups.key(brick_id)) {
33436 return this.groups.key(brick_id);
33454 * @class Roo.bootstrap.Brick
33455 * @extends Roo.bootstrap.Component
33456 * Bootstrap Brick class
33459 * Create a new Brick
33460 * @param {Object} config The config object
33463 Roo.bootstrap.Brick = function(config){
33464 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33470 * When a Brick is click
33471 * @param {Roo.bootstrap.Brick} this
33472 * @param {Roo.EventObject} e
33478 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33481 * @cfg {String} title
33485 * @cfg {String} html
33489 * @cfg {String} bgimage
33493 * @cfg {String} cls
33497 * @cfg {String} href
33501 * @cfg {String} video
33505 * @cfg {Boolean} square
33509 getAutoCreate : function()
33511 var cls = 'roo-brick';
33513 if(this.href.length){
33514 cls += ' roo-brick-link';
33517 if(this.bgimage.length){
33518 cls += ' roo-brick-image';
33521 if(!this.html.length && !this.bgimage.length){
33522 cls += ' roo-brick-center-title';
33525 if(!this.html.length && this.bgimage.length){
33526 cls += ' roo-brick-bottom-title';
33530 cls += ' ' + this.cls;
33534 tag: (this.href.length) ? 'a' : 'div',
33539 cls: 'roo-brick-paragraph',
33545 if(this.href.length){
33546 cfg.href = this.href;
33549 var cn = cfg.cn[0].cn;
33551 if(this.title.length){
33554 cls: 'roo-brick-title',
33559 if(this.html.length){
33562 cls: 'roo-brick-text',
33569 if(this.bgimage.length){
33572 cls: 'roo-brick-image-view',
33580 initEvents: function()
33582 if(this.title.length || this.html.length){
33583 this.el.on('mouseenter' ,this.enter, this);
33584 this.el.on('mouseleave', this.leave, this);
33587 Roo.EventManager.onWindowResize(this.resize, this);
33589 if(this.bgimage.length){
33590 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33591 this.imageEl.on('load', this.onImageLoad, this);
33598 onImageLoad : function()
33603 resize : function()
33605 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33607 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33609 if(this.bgimage.length){
33610 var image = this.el.select('.roo-brick-image-view', true).first();
33612 image.setWidth(paragraph.getWidth());
33615 image.setHeight(paragraph.getWidth());
33618 this.el.setHeight(image.getHeight());
33619 paragraph.setHeight(image.getHeight());
33625 enter: function(e, el)
33627 e.preventDefault();
33629 if(this.bgimage.length){
33630 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33631 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33635 leave: function(e, el)
33637 e.preventDefault();
33639 if(this.bgimage.length){
33640 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33641 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33656 * @class Roo.bootstrap.NumberField
33657 * @extends Roo.bootstrap.Input
33658 * Bootstrap NumberField class
33664 * Create a new NumberField
33665 * @param {Object} config The config object
33668 Roo.bootstrap.NumberField = function(config){
33669 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33672 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33675 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33677 allowDecimals : true,
33679 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33681 decimalSeparator : ".",
33683 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33685 decimalPrecision : 2,
33687 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33689 allowNegative : true,
33692 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33696 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33698 minValue : Number.NEGATIVE_INFINITY,
33700 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33702 maxValue : Number.MAX_VALUE,
33704 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33706 minText : "The minimum value for this field is {0}",
33708 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33710 maxText : "The maximum value for this field is {0}",
33712 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33713 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33715 nanText : "{0} is not a valid number",
33717 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33719 thousandsDelimiter : false,
33721 * @cfg {String} valueAlign alignment of value
33723 valueAlign : "left",
33725 getAutoCreate : function()
33727 var hiddenInput = {
33731 cls: 'hidden-number-input'
33735 hiddenInput.name = this.name;
33740 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33742 this.name = hiddenInput.name;
33744 if(cfg.cn.length > 0) {
33745 cfg.cn.push(hiddenInput);
33752 initEvents : function()
33754 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33756 var allowed = "0123456789";
33758 if(this.allowDecimals){
33759 allowed += this.decimalSeparator;
33762 if(this.allowNegative){
33766 if(this.thousandsDelimiter) {
33770 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33772 var keyPress = function(e){
33774 var k = e.getKey();
33776 var c = e.getCharCode();
33779 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33780 allowed.indexOf(String.fromCharCode(c)) === -1
33786 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33790 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33795 this.el.on("keypress", keyPress, this);
33798 validateValue : function(value)
33801 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33805 var num = this.parseValue(value);
33808 this.markInvalid(String.format(this.nanText, value));
33812 if(num < this.minValue){
33813 this.markInvalid(String.format(this.minText, this.minValue));
33817 if(num > this.maxValue){
33818 this.markInvalid(String.format(this.maxText, this.maxValue));
33825 getValue : function()
33827 var v = this.hiddenEl().getValue();
33829 return this.fixPrecision(this.parseValue(v));
33832 parseValue : function(value)
33834 if(this.thousandsDelimiter) {
33836 r = new RegExp(",", "g");
33837 value = value.replace(r, "");
33840 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33841 return isNaN(value) ? '' : value;
33844 fixPrecision : function(value)
33846 if(this.thousandsDelimiter) {
33848 r = new RegExp(",", "g");
33849 value = value.replace(r, "");
33852 var nan = isNaN(value);
33854 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33855 return nan ? '' : value;
33857 return parseFloat(value).toFixed(this.decimalPrecision);
33860 setValue : function(v)
33862 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33868 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33870 this.inputEl().dom.value = (v == '') ? '' :
33871 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33873 if(!this.allowZero && v === '0') {
33874 this.hiddenEl().dom.value = '';
33875 this.inputEl().dom.value = '';
33882 decimalPrecisionFcn : function(v)
33884 return Math.floor(v);
33887 beforeBlur : function()
33889 var v = this.parseValue(this.getRawValue());
33891 if(v || v === 0 || v === ''){
33896 hiddenEl : function()
33898 return this.el.select('input.hidden-number-input',true).first();
33910 * @class Roo.bootstrap.DocumentSlider
33911 * @extends Roo.bootstrap.Component
33912 * Bootstrap DocumentSlider class
33915 * Create a new DocumentViewer
33916 * @param {Object} config The config object
33919 Roo.bootstrap.DocumentSlider = function(config){
33920 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33927 * Fire after initEvent
33928 * @param {Roo.bootstrap.DocumentSlider} this
33933 * Fire after update
33934 * @param {Roo.bootstrap.DocumentSlider} this
33940 * @param {Roo.bootstrap.DocumentSlider} this
33946 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33952 getAutoCreate : function()
33956 cls : 'roo-document-slider',
33960 cls : 'roo-document-slider-header',
33964 cls : 'roo-document-slider-header-title'
33970 cls : 'roo-document-slider-body',
33974 cls : 'roo-document-slider-prev',
33978 cls : 'fa fa-chevron-left'
33984 cls : 'roo-document-slider-thumb',
33988 cls : 'roo-document-slider-image'
33994 cls : 'roo-document-slider-next',
33998 cls : 'fa fa-chevron-right'
34010 initEvents : function()
34012 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34013 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34015 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34016 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34018 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34019 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34021 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34022 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34024 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34025 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34027 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34028 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34030 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34031 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34033 this.thumbEl.on('click', this.onClick, this);
34035 this.prevIndicator.on('click', this.prev, this);
34037 this.nextIndicator.on('click', this.next, this);
34041 initial : function()
34043 if(this.files.length){
34044 this.indicator = 1;
34048 this.fireEvent('initial', this);
34051 update : function()
34053 this.imageEl.attr('src', this.files[this.indicator - 1]);
34055 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34057 this.prevIndicator.show();
34059 if(this.indicator == 1){
34060 this.prevIndicator.hide();
34063 this.nextIndicator.show();
34065 if(this.indicator == this.files.length){
34066 this.nextIndicator.hide();
34069 this.thumbEl.scrollTo('top');
34071 this.fireEvent('update', this);
34074 onClick : function(e)
34076 e.preventDefault();
34078 this.fireEvent('click', this);
34083 e.preventDefault();
34085 this.indicator = Math.max(1, this.indicator - 1);
34092 e.preventDefault();
34094 this.indicator = Math.min(this.files.length, this.indicator + 1);
34108 * @class Roo.bootstrap.RadioSet
34109 * @extends Roo.bootstrap.Input
34110 * Bootstrap RadioSet class
34111 * @cfg {String} indicatorpos (left|right) default left
34112 * @cfg {Boolean} inline (true|false) inline the element (default true)
34113 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34115 * Create a new RadioSet
34116 * @param {Object} config The config object
34119 Roo.bootstrap.RadioSet = function(config){
34121 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34125 Roo.bootstrap.RadioSet.register(this);
34130 * Fires when the element is checked or unchecked.
34131 * @param {Roo.bootstrap.RadioSet} this This radio
34132 * @param {Roo.bootstrap.Radio} item The checked item
34137 * Fires when the element is click.
34138 * @param {Roo.bootstrap.RadioSet} this This radio set
34139 * @param {Roo.bootstrap.Radio} item The checked item
34140 * @param {Roo.EventObject} e The event object
34147 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34155 indicatorpos : 'left',
34157 getAutoCreate : function()
34161 cls : 'roo-radio-set-label',
34165 html : this.fieldLabel
34169 if (Roo.bootstrap.version == 3) {
34172 if(this.indicatorpos == 'left'){
34175 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34176 tooltip : 'This field is required'
34181 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34182 tooltip : 'This field is required'
34188 cls : 'roo-radio-set-items'
34191 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34193 if (align === 'left' && this.fieldLabel.length) {
34196 cls : "roo-radio-set-right",
34202 if(this.labelWidth > 12){
34203 label.style = "width: " + this.labelWidth + 'px';
34206 if(this.labelWidth < 13 && this.labelmd == 0){
34207 this.labelmd = this.labelWidth;
34210 if(this.labellg > 0){
34211 label.cls += ' col-lg-' + this.labellg;
34212 items.cls += ' col-lg-' + (12 - this.labellg);
34215 if(this.labelmd > 0){
34216 label.cls += ' col-md-' + this.labelmd;
34217 items.cls += ' col-md-' + (12 - this.labelmd);
34220 if(this.labelsm > 0){
34221 label.cls += ' col-sm-' + this.labelsm;
34222 items.cls += ' col-sm-' + (12 - this.labelsm);
34225 if(this.labelxs > 0){
34226 label.cls += ' col-xs-' + this.labelxs;
34227 items.cls += ' col-xs-' + (12 - this.labelxs);
34233 cls : 'roo-radio-set',
34237 cls : 'roo-radio-set-input',
34240 value : this.value ? this.value : ''
34247 if(this.weight.length){
34248 cfg.cls += ' roo-radio-' + this.weight;
34252 cfg.cls += ' roo-radio-set-inline';
34256 ['xs','sm','md','lg'].map(function(size){
34257 if (settings[size]) {
34258 cfg.cls += ' col-' + size + '-' + settings[size];
34266 initEvents : function()
34268 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34269 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34271 if(!this.fieldLabel.length){
34272 this.labelEl.hide();
34275 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34276 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34278 this.indicator = this.indicatorEl();
34280 if(this.indicator){
34281 this.indicator.addClass('invisible');
34284 this.originalValue = this.getValue();
34288 inputEl: function ()
34290 return this.el.select('.roo-radio-set-input', true).first();
34293 getChildContainer : function()
34295 return this.itemsEl;
34298 register : function(item)
34300 this.radioes.push(item);
34304 validate : function()
34306 if(this.getVisibilityEl().hasClass('hidden')){
34312 Roo.each(this.radioes, function(i){
34321 if(this.allowBlank) {
34325 if(this.disabled || valid){
34330 this.markInvalid();
34335 markValid : function()
34337 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34338 this.indicatorEl().removeClass('visible');
34339 this.indicatorEl().addClass('invisible');
34343 if (Roo.bootstrap.version == 3) {
34344 this.el.removeClass([this.invalidClass, this.validClass]);
34345 this.el.addClass(this.validClass);
34347 this.el.removeClass(['is-invalid','is-valid']);
34348 this.el.addClass(['is-valid']);
34350 this.fireEvent('valid', this);
34353 markInvalid : function(msg)
34355 if(this.allowBlank || this.disabled){
34359 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34360 this.indicatorEl().removeClass('invisible');
34361 this.indicatorEl().addClass('visible');
34363 if (Roo.bootstrap.version == 3) {
34364 this.el.removeClass([this.invalidClass, this.validClass]);
34365 this.el.addClass(this.invalidClass);
34367 this.el.removeClass(['is-invalid','is-valid']);
34368 this.el.addClass(['is-invalid']);
34371 this.fireEvent('invalid', this, msg);
34375 setValue : function(v, suppressEvent)
34377 if(this.value === v){
34384 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34387 Roo.each(this.radioes, function(i){
34389 i.el.removeClass('checked');
34392 Roo.each(this.radioes, function(i){
34394 if(i.value === v || i.value.toString() === v.toString()){
34396 i.el.addClass('checked');
34398 if(suppressEvent !== true){
34399 this.fireEvent('check', this, i);
34410 clearInvalid : function(){
34412 if(!this.el || this.preventMark){
34416 this.el.removeClass([this.invalidClass]);
34418 this.fireEvent('valid', this);
34423 Roo.apply(Roo.bootstrap.RadioSet, {
34427 register : function(set)
34429 this.groups[set.name] = set;
34432 get: function(name)
34434 if (typeof(this.groups[name]) == 'undefined') {
34438 return this.groups[name] ;
34444 * Ext JS Library 1.1.1
34445 * Copyright(c) 2006-2007, Ext JS, LLC.
34447 * Originally Released Under LGPL - original licence link has changed is not relivant.
34450 * <script type="text/javascript">
34455 * @class Roo.bootstrap.SplitBar
34456 * @extends Roo.util.Observable
34457 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34461 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34462 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34463 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34464 split.minSize = 100;
34465 split.maxSize = 600;
34466 split.animate = true;
34467 split.on('moved', splitterMoved);
34470 * Create a new SplitBar
34471 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34472 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34473 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34474 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34475 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34476 position of the SplitBar).
34478 Roo.bootstrap.SplitBar = function(cfg){
34483 // dragElement : elm
34484 // resizingElement: el,
34486 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34487 // placement : Roo.bootstrap.SplitBar.LEFT ,
34488 // existingProxy ???
34491 this.el = Roo.get(cfg.dragElement, true);
34492 this.el.dom.unselectable = "on";
34494 this.resizingEl = Roo.get(cfg.resizingElement, true);
34498 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34499 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34502 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34505 * The minimum size of the resizing element. (Defaults to 0)
34511 * The maximum size of the resizing element. (Defaults to 2000)
34514 this.maxSize = 2000;
34517 * Whether to animate the transition to the new size
34520 this.animate = false;
34523 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34526 this.useShim = false;
34531 if(!cfg.existingProxy){
34533 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34535 this.proxy = Roo.get(cfg.existingProxy).dom;
34538 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34541 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34544 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34547 this.dragSpecs = {};
34550 * @private The adapter to use to positon and resize elements
34552 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34553 this.adapter.init(this);
34555 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34557 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34558 this.el.addClass("roo-splitbar-h");
34561 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34562 this.el.addClass("roo-splitbar-v");
34568 * Fires when the splitter is moved (alias for {@link #event-moved})
34569 * @param {Roo.bootstrap.SplitBar} this
34570 * @param {Number} newSize the new width or height
34575 * Fires when the splitter is moved
34576 * @param {Roo.bootstrap.SplitBar} this
34577 * @param {Number} newSize the new width or height
34581 * @event beforeresize
34582 * Fires before the splitter is dragged
34583 * @param {Roo.bootstrap.SplitBar} this
34585 "beforeresize" : true,
34587 "beforeapply" : true
34590 Roo.util.Observable.call(this);
34593 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34594 onStartProxyDrag : function(x, y){
34595 this.fireEvent("beforeresize", this);
34597 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34599 o.enableDisplayMode("block");
34600 // all splitbars share the same overlay
34601 Roo.bootstrap.SplitBar.prototype.overlay = o;
34603 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34604 this.overlay.show();
34605 Roo.get(this.proxy).setDisplayed("block");
34606 var size = this.adapter.getElementSize(this);
34607 this.activeMinSize = this.getMinimumSize();;
34608 this.activeMaxSize = this.getMaximumSize();;
34609 var c1 = size - this.activeMinSize;
34610 var c2 = Math.max(this.activeMaxSize - size, 0);
34611 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34612 this.dd.resetConstraints();
34613 this.dd.setXConstraint(
34614 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34615 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34617 this.dd.setYConstraint(0, 0);
34619 this.dd.resetConstraints();
34620 this.dd.setXConstraint(0, 0);
34621 this.dd.setYConstraint(
34622 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34623 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34626 this.dragSpecs.startSize = size;
34627 this.dragSpecs.startPoint = [x, y];
34628 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34632 * @private Called after the drag operation by the DDProxy
34634 onEndProxyDrag : function(e){
34635 Roo.get(this.proxy).setDisplayed(false);
34636 var endPoint = Roo.lib.Event.getXY(e);
34638 this.overlay.hide();
34641 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34642 newSize = this.dragSpecs.startSize +
34643 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34644 endPoint[0] - this.dragSpecs.startPoint[0] :
34645 this.dragSpecs.startPoint[0] - endPoint[0]
34648 newSize = this.dragSpecs.startSize +
34649 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34650 endPoint[1] - this.dragSpecs.startPoint[1] :
34651 this.dragSpecs.startPoint[1] - endPoint[1]
34654 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34655 if(newSize != this.dragSpecs.startSize){
34656 if(this.fireEvent('beforeapply', this, newSize) !== false){
34657 this.adapter.setElementSize(this, newSize);
34658 this.fireEvent("moved", this, newSize);
34659 this.fireEvent("resize", this, newSize);
34665 * Get the adapter this SplitBar uses
34666 * @return The adapter object
34668 getAdapter : function(){
34669 return this.adapter;
34673 * Set the adapter this SplitBar uses
34674 * @param {Object} adapter A SplitBar adapter object
34676 setAdapter : function(adapter){
34677 this.adapter = adapter;
34678 this.adapter.init(this);
34682 * Gets the minimum size for the resizing element
34683 * @return {Number} The minimum size
34685 getMinimumSize : function(){
34686 return this.minSize;
34690 * Sets the minimum size for the resizing element
34691 * @param {Number} minSize The minimum size
34693 setMinimumSize : function(minSize){
34694 this.minSize = minSize;
34698 * Gets the maximum size for the resizing element
34699 * @return {Number} The maximum size
34701 getMaximumSize : function(){
34702 return this.maxSize;
34706 * Sets the maximum size for the resizing element
34707 * @param {Number} maxSize The maximum size
34709 setMaximumSize : function(maxSize){
34710 this.maxSize = maxSize;
34714 * Sets the initialize size for the resizing element
34715 * @param {Number} size The initial size
34717 setCurrentSize : function(size){
34718 var oldAnimate = this.animate;
34719 this.animate = false;
34720 this.adapter.setElementSize(this, size);
34721 this.animate = oldAnimate;
34725 * Destroy this splitbar.
34726 * @param {Boolean} removeEl True to remove the element
34728 destroy : function(removeEl){
34730 this.shim.remove();
34733 this.proxy.parentNode.removeChild(this.proxy);
34741 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
34743 Roo.bootstrap.SplitBar.createProxy = function(dir){
34744 var proxy = new Roo.Element(document.createElement("div"));
34745 proxy.unselectable();
34746 var cls = 'roo-splitbar-proxy';
34747 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34748 document.body.appendChild(proxy.dom);
34753 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34754 * Default Adapter. It assumes the splitter and resizing element are not positioned
34755 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34757 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34760 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34761 // do nothing for now
34762 init : function(s){
34766 * Called before drag operations to get the current size of the resizing element.
34767 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34769 getElementSize : function(s){
34770 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34771 return s.resizingEl.getWidth();
34773 return s.resizingEl.getHeight();
34778 * Called after drag operations to set the size of the resizing element.
34779 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34780 * @param {Number} newSize The new size to set
34781 * @param {Function} onComplete A function to be invoked when resizing is complete
34783 setElementSize : function(s, newSize, onComplete){
34784 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34786 s.resizingEl.setWidth(newSize);
34788 onComplete(s, newSize);
34791 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34796 s.resizingEl.setHeight(newSize);
34798 onComplete(s, newSize);
34801 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34808 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34809 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34810 * Adapter that moves the splitter element to align with the resized sizing element.
34811 * Used with an absolute positioned SplitBar.
34812 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34813 * document.body, make sure you assign an id to the body element.
34815 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34816 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34817 this.container = Roo.get(container);
34820 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34821 init : function(s){
34822 this.basic.init(s);
34825 getElementSize : function(s){
34826 return this.basic.getElementSize(s);
34829 setElementSize : function(s, newSize, onComplete){
34830 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34833 moveSplitter : function(s){
34834 var yes = Roo.bootstrap.SplitBar;
34835 switch(s.placement){
34837 s.el.setX(s.resizingEl.getRight());
34840 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34843 s.el.setY(s.resizingEl.getBottom());
34846 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34853 * Orientation constant - Create a vertical SplitBar
34857 Roo.bootstrap.SplitBar.VERTICAL = 1;
34860 * Orientation constant - Create a horizontal SplitBar
34864 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34867 * Placement constant - The resizing element is to the left of the splitter element
34871 Roo.bootstrap.SplitBar.LEFT = 1;
34874 * Placement constant - The resizing element is to the right of the splitter element
34878 Roo.bootstrap.SplitBar.RIGHT = 2;
34881 * Placement constant - The resizing element is positioned above the splitter element
34885 Roo.bootstrap.SplitBar.TOP = 3;
34888 * Placement constant - The resizing element is positioned under splitter element
34892 Roo.bootstrap.SplitBar.BOTTOM = 4;
34893 Roo.namespace("Roo.bootstrap.layout");/*
34895 * Ext JS Library 1.1.1
34896 * Copyright(c) 2006-2007, Ext JS, LLC.
34898 * Originally Released Under LGPL - original licence link has changed is not relivant.
34901 * <script type="text/javascript">
34905 * @class Roo.bootstrap.layout.Manager
34906 * @extends Roo.bootstrap.Component
34907 * Base class for layout managers.
34909 Roo.bootstrap.layout.Manager = function(config)
34911 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34917 /** false to disable window resize monitoring @type Boolean */
34918 this.monitorWindowResize = true;
34923 * Fires when a layout is performed.
34924 * @param {Roo.LayoutManager} this
34928 * @event regionresized
34929 * Fires when the user resizes a region.
34930 * @param {Roo.LayoutRegion} region The resized region
34931 * @param {Number} newSize The new size (width for east/west, height for north/south)
34933 "regionresized" : true,
34935 * @event regioncollapsed
34936 * Fires when a region is collapsed.
34937 * @param {Roo.LayoutRegion} region The collapsed region
34939 "regioncollapsed" : true,
34941 * @event regionexpanded
34942 * Fires when a region is expanded.
34943 * @param {Roo.LayoutRegion} region The expanded region
34945 "regionexpanded" : true
34947 this.updating = false;
34950 this.el = Roo.get(config.el);
34956 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34961 monitorWindowResize : true,
34967 onRender : function(ct, position)
34970 this.el = Roo.get(ct);
34973 //this.fireEvent('render',this);
34977 initEvents: function()
34981 // ie scrollbar fix
34982 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34983 document.body.scroll = "no";
34984 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34985 this.el.position('relative');
34987 this.id = this.el.id;
34988 this.el.addClass("roo-layout-container");
34989 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34990 if(this.el.dom != document.body ) {
34991 this.el.on('resize', this.layout,this);
34992 this.el.on('show', this.layout,this);
34998 * Returns true if this layout is currently being updated
34999 * @return {Boolean}
35001 isUpdating : function(){
35002 return this.updating;
35006 * Suspend the LayoutManager from doing auto-layouts while
35007 * making multiple add or remove calls
35009 beginUpdate : function(){
35010 this.updating = true;
35014 * Restore auto-layouts and optionally disable the manager from performing a layout
35015 * @param {Boolean} noLayout true to disable a layout update
35017 endUpdate : function(noLayout){
35018 this.updating = false;
35024 layout: function(){
35028 onRegionResized : function(region, newSize){
35029 this.fireEvent("regionresized", region, newSize);
35033 onRegionCollapsed : function(region){
35034 this.fireEvent("regioncollapsed", region);
35037 onRegionExpanded : function(region){
35038 this.fireEvent("regionexpanded", region);
35042 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35043 * performs box-model adjustments.
35044 * @return {Object} The size as an object {width: (the width), height: (the height)}
35046 getViewSize : function()
35049 if(this.el.dom != document.body){
35050 size = this.el.getSize();
35052 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35054 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35055 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35060 * Returns the Element this layout is bound to.
35061 * @return {Roo.Element}
35063 getEl : function(){
35068 * Returns the specified region.
35069 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35070 * @return {Roo.LayoutRegion}
35072 getRegion : function(target){
35073 return this.regions[target.toLowerCase()];
35076 onWindowResize : function(){
35077 if(this.monitorWindowResize){
35084 * Ext JS Library 1.1.1
35085 * Copyright(c) 2006-2007, Ext JS, LLC.
35087 * Originally Released Under LGPL - original licence link has changed is not relivant.
35090 * <script type="text/javascript">
35093 * @class Roo.bootstrap.layout.Border
35094 * @extends Roo.bootstrap.layout.Manager
35095 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35096 * please see: examples/bootstrap/nested.html<br><br>
35098 <b>The container the layout is rendered into can be either the body element or any other element.
35099 If it is not the body element, the container needs to either be an absolute positioned element,
35100 or you will need to add "position:relative" to the css of the container. You will also need to specify
35101 the container size if it is not the body element.</b>
35104 * Create a new Border
35105 * @param {Object} config Configuration options
35107 Roo.bootstrap.layout.Border = function(config){
35108 config = config || {};
35109 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35113 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35114 if(config[region]){
35115 config[region].region = region;
35116 this.addRegion(config[region]);
35122 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35124 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35126 * Creates and adds a new region if it doesn't already exist.
35127 * @param {String} target The target region key (north, south, east, west or center).
35128 * @param {Object} config The regions config object
35129 * @return {BorderLayoutRegion} The new region
35131 addRegion : function(config)
35133 if(!this.regions[config.region]){
35134 var r = this.factory(config);
35135 this.bindRegion(r);
35137 return this.regions[config.region];
35141 bindRegion : function(r){
35142 this.regions[r.config.region] = r;
35144 r.on("visibilitychange", this.layout, this);
35145 r.on("paneladded", this.layout, this);
35146 r.on("panelremoved", this.layout, this);
35147 r.on("invalidated", this.layout, this);
35148 r.on("resized", this.onRegionResized, this);
35149 r.on("collapsed", this.onRegionCollapsed, this);
35150 r.on("expanded", this.onRegionExpanded, this);
35154 * Performs a layout update.
35156 layout : function()
35158 if(this.updating) {
35162 // render all the rebions if they have not been done alreayd?
35163 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35164 if(this.regions[region] && !this.regions[region].bodyEl){
35165 this.regions[region].onRender(this.el)
35169 var size = this.getViewSize();
35170 var w = size.width;
35171 var h = size.height;
35176 //var x = 0, y = 0;
35178 var rs = this.regions;
35179 var north = rs["north"];
35180 var south = rs["south"];
35181 var west = rs["west"];
35182 var east = rs["east"];
35183 var center = rs["center"];
35184 //if(this.hideOnLayout){ // not supported anymore
35185 //c.el.setStyle("display", "none");
35187 if(north && north.isVisible()){
35188 var b = north.getBox();
35189 var m = north.getMargins();
35190 b.width = w - (m.left+m.right);
35193 centerY = b.height + b.y + m.bottom;
35194 centerH -= centerY;
35195 north.updateBox(this.safeBox(b));
35197 if(south && south.isVisible()){
35198 var b = south.getBox();
35199 var m = south.getMargins();
35200 b.width = w - (m.left+m.right);
35202 var totalHeight = (b.height + m.top + m.bottom);
35203 b.y = h - totalHeight + m.top;
35204 centerH -= totalHeight;
35205 south.updateBox(this.safeBox(b));
35207 if(west && west.isVisible()){
35208 var b = west.getBox();
35209 var m = west.getMargins();
35210 b.height = centerH - (m.top+m.bottom);
35212 b.y = centerY + m.top;
35213 var totalWidth = (b.width + m.left + m.right);
35214 centerX += totalWidth;
35215 centerW -= totalWidth;
35216 west.updateBox(this.safeBox(b));
35218 if(east && east.isVisible()){
35219 var b = east.getBox();
35220 var m = east.getMargins();
35221 b.height = centerH - (m.top+m.bottom);
35222 var totalWidth = (b.width + m.left + m.right);
35223 b.x = w - totalWidth + m.left;
35224 b.y = centerY + m.top;
35225 centerW -= totalWidth;
35226 east.updateBox(this.safeBox(b));
35229 var m = center.getMargins();
35231 x: centerX + m.left,
35232 y: centerY + m.top,
35233 width: centerW - (m.left+m.right),
35234 height: centerH - (m.top+m.bottom)
35236 //if(this.hideOnLayout){
35237 //center.el.setStyle("display", "block");
35239 center.updateBox(this.safeBox(centerBox));
35242 this.fireEvent("layout", this);
35246 safeBox : function(box){
35247 box.width = Math.max(0, box.width);
35248 box.height = Math.max(0, box.height);
35253 * Adds a ContentPanel (or subclass) to this layout.
35254 * @param {String} target The target region key (north, south, east, west or center).
35255 * @param {Roo.ContentPanel} panel The panel to add
35256 * @return {Roo.ContentPanel} The added panel
35258 add : function(target, panel){
35260 target = target.toLowerCase();
35261 return this.regions[target].add(panel);
35265 * Remove a ContentPanel (or subclass) to this layout.
35266 * @param {String} target The target region key (north, south, east, west or center).
35267 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35268 * @return {Roo.ContentPanel} The removed panel
35270 remove : function(target, panel){
35271 target = target.toLowerCase();
35272 return this.regions[target].remove(panel);
35276 * Searches all regions for a panel with the specified id
35277 * @param {String} panelId
35278 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35280 findPanel : function(panelId){
35281 var rs = this.regions;
35282 for(var target in rs){
35283 if(typeof rs[target] != "function"){
35284 var p = rs[target].getPanel(panelId);
35294 * Searches all regions for a panel with the specified id and activates (shows) it.
35295 * @param {String/ContentPanel} panelId The panels id or the panel itself
35296 * @return {Roo.ContentPanel} The shown panel or null
35298 showPanel : function(panelId) {
35299 var rs = this.regions;
35300 for(var target in rs){
35301 var r = rs[target];
35302 if(typeof r != "function"){
35303 if(r.hasPanel(panelId)){
35304 return r.showPanel(panelId);
35312 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35313 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35316 restoreState : function(provider){
35318 provider = Roo.state.Manager;
35320 var sm = new Roo.LayoutStateManager();
35321 sm.init(this, provider);
35327 * Adds a xtype elements to the layout.
35331 xtype : 'ContentPanel',
35338 xtype : 'NestedLayoutPanel',
35344 items : [ ... list of content panels or nested layout panels.. ]
35348 * @param {Object} cfg Xtype definition of item to add.
35350 addxtype : function(cfg)
35352 // basically accepts a pannel...
35353 // can accept a layout region..!?!?
35354 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35357 // theory? children can only be panels??
35359 //if (!cfg.xtype.match(/Panel$/)) {
35364 if (typeof(cfg.region) == 'undefined') {
35365 Roo.log("Failed to add Panel, region was not set");
35369 var region = cfg.region;
35375 xitems = cfg.items;
35382 case 'Content': // ContentPanel (el, cfg)
35383 case 'Scroll': // ContentPanel (el, cfg)
35385 cfg.autoCreate = true;
35386 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35388 // var el = this.el.createChild();
35389 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35392 this.add(region, ret);
35396 case 'TreePanel': // our new panel!
35397 cfg.el = this.el.createChild();
35398 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35399 this.add(region, ret);
35404 // create a new Layout (which is a Border Layout...
35406 var clayout = cfg.layout;
35407 clayout.el = this.el.createChild();
35408 clayout.items = clayout.items || [];
35412 // replace this exitems with the clayout ones..
35413 xitems = clayout.items;
35415 // force background off if it's in center...
35416 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35417 cfg.background = false;
35419 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35422 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35423 //console.log('adding nested layout panel ' + cfg.toSource());
35424 this.add(region, ret);
35425 nb = {}; /// find first...
35430 // needs grid and region
35432 //var el = this.getRegion(region).el.createChild();
35434 *var el = this.el.createChild();
35435 // create the grid first...
35436 cfg.grid.container = el;
35437 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35440 if (region == 'center' && this.active ) {
35441 cfg.background = false;
35444 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35446 this.add(region, ret);
35448 if (cfg.background) {
35449 // render grid on panel activation (if panel background)
35450 ret.on('activate', function(gp) {
35451 if (!gp.grid.rendered) {
35452 // gp.grid.render(el);
35456 // cfg.grid.render(el);
35462 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35463 // it was the old xcomponent building that caused this before.
35464 // espeically if border is the top element in the tree.
35474 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35476 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35477 this.add(region, ret);
35481 throw "Can not add '" + cfg.xtype + "' to Border";
35487 this.beginUpdate();
35491 Roo.each(xitems, function(i) {
35492 region = nb && i.region ? i.region : false;
35494 var add = ret.addxtype(i);
35497 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35498 if (!i.background) {
35499 abn[region] = nb[region] ;
35506 // make the last non-background panel active..
35507 //if (nb) { Roo.log(abn); }
35510 for(var r in abn) {
35511 region = this.getRegion(r);
35513 // tried using nb[r], but it does not work..
35515 region.showPanel(abn[r]);
35526 factory : function(cfg)
35529 var validRegions = Roo.bootstrap.layout.Border.regions;
35531 var target = cfg.region;
35534 var r = Roo.bootstrap.layout;
35538 return new r.North(cfg);
35540 return new r.South(cfg);
35542 return new r.East(cfg);
35544 return new r.West(cfg);
35546 return new r.Center(cfg);
35548 throw 'Layout region "'+target+'" not supported.';
35555 * Ext JS Library 1.1.1
35556 * Copyright(c) 2006-2007, Ext JS, LLC.
35558 * Originally Released Under LGPL - original licence link has changed is not relivant.
35561 * <script type="text/javascript">
35565 * @class Roo.bootstrap.layout.Basic
35566 * @extends Roo.util.Observable
35567 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35568 * and does not have a titlebar, tabs or any other features. All it does is size and position
35569 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35570 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35571 * @cfg {string} region the region that it inhabits..
35572 * @cfg {bool} skipConfig skip config?
35576 Roo.bootstrap.layout.Basic = function(config){
35578 this.mgr = config.mgr;
35580 this.position = config.region;
35582 var skipConfig = config.skipConfig;
35586 * @scope Roo.BasicLayoutRegion
35590 * @event beforeremove
35591 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35592 * @param {Roo.LayoutRegion} this
35593 * @param {Roo.ContentPanel} panel The panel
35594 * @param {Object} e The cancel event object
35596 "beforeremove" : true,
35598 * @event invalidated
35599 * Fires when the layout for this region is changed.
35600 * @param {Roo.LayoutRegion} this
35602 "invalidated" : true,
35604 * @event visibilitychange
35605 * Fires when this region is shown or hidden
35606 * @param {Roo.LayoutRegion} this
35607 * @param {Boolean} visibility true or false
35609 "visibilitychange" : true,
35611 * @event paneladded
35612 * Fires when a panel is added.
35613 * @param {Roo.LayoutRegion} this
35614 * @param {Roo.ContentPanel} panel The panel
35616 "paneladded" : true,
35618 * @event panelremoved
35619 * Fires when a panel is removed.
35620 * @param {Roo.LayoutRegion} this
35621 * @param {Roo.ContentPanel} panel The panel
35623 "panelremoved" : true,
35625 * @event beforecollapse
35626 * Fires when this region before collapse.
35627 * @param {Roo.LayoutRegion} this
35629 "beforecollapse" : true,
35632 * Fires when this region is collapsed.
35633 * @param {Roo.LayoutRegion} this
35635 "collapsed" : true,
35638 * Fires when this region is expanded.
35639 * @param {Roo.LayoutRegion} this
35644 * Fires when this region is slid into view.
35645 * @param {Roo.LayoutRegion} this
35647 "slideshow" : true,
35650 * Fires when this region slides out of view.
35651 * @param {Roo.LayoutRegion} this
35653 "slidehide" : true,
35655 * @event panelactivated
35656 * Fires when a panel is activated.
35657 * @param {Roo.LayoutRegion} this
35658 * @param {Roo.ContentPanel} panel The activated panel
35660 "panelactivated" : true,
35663 * Fires when the user resizes this region.
35664 * @param {Roo.LayoutRegion} this
35665 * @param {Number} newSize The new size (width for east/west, height for north/south)
35669 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35670 this.panels = new Roo.util.MixedCollection();
35671 this.panels.getKey = this.getPanelId.createDelegate(this);
35673 this.activePanel = null;
35674 // ensure listeners are added...
35676 if (config.listeners || config.events) {
35677 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35678 listeners : config.listeners || {},
35679 events : config.events || {}
35683 if(skipConfig !== true){
35684 this.applyConfig(config);
35688 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35690 getPanelId : function(p){
35694 applyConfig : function(config){
35695 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35696 this.config = config;
35701 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35702 * the width, for horizontal (north, south) the height.
35703 * @param {Number} newSize The new width or height
35705 resizeTo : function(newSize){
35706 var el = this.el ? this.el :
35707 (this.activePanel ? this.activePanel.getEl() : null);
35709 switch(this.position){
35712 el.setWidth(newSize);
35713 this.fireEvent("resized", this, newSize);
35717 el.setHeight(newSize);
35718 this.fireEvent("resized", this, newSize);
35724 getBox : function(){
35725 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35728 getMargins : function(){
35729 return this.margins;
35732 updateBox : function(box){
35734 var el = this.activePanel.getEl();
35735 el.dom.style.left = box.x + "px";
35736 el.dom.style.top = box.y + "px";
35737 this.activePanel.setSize(box.width, box.height);
35741 * Returns the container element for this region.
35742 * @return {Roo.Element}
35744 getEl : function(){
35745 return this.activePanel;
35749 * Returns true if this region is currently visible.
35750 * @return {Boolean}
35752 isVisible : function(){
35753 return this.activePanel ? true : false;
35756 setActivePanel : function(panel){
35757 panel = this.getPanel(panel);
35758 if(this.activePanel && this.activePanel != panel){
35759 this.activePanel.setActiveState(false);
35760 this.activePanel.getEl().setLeftTop(-10000,-10000);
35762 this.activePanel = panel;
35763 panel.setActiveState(true);
35765 panel.setSize(this.box.width, this.box.height);
35767 this.fireEvent("panelactivated", this, panel);
35768 this.fireEvent("invalidated");
35772 * Show the specified panel.
35773 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35774 * @return {Roo.ContentPanel} The shown panel or null
35776 showPanel : function(panel){
35777 panel = this.getPanel(panel);
35779 this.setActivePanel(panel);
35785 * Get the active panel for this region.
35786 * @return {Roo.ContentPanel} The active panel or null
35788 getActivePanel : function(){
35789 return this.activePanel;
35793 * Add the passed ContentPanel(s)
35794 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35795 * @return {Roo.ContentPanel} The panel added (if only one was added)
35797 add : function(panel){
35798 if(arguments.length > 1){
35799 for(var i = 0, len = arguments.length; i < len; i++) {
35800 this.add(arguments[i]);
35804 if(this.hasPanel(panel)){
35805 this.showPanel(panel);
35808 var el = panel.getEl();
35809 if(el.dom.parentNode != this.mgr.el.dom){
35810 this.mgr.el.dom.appendChild(el.dom);
35812 if(panel.setRegion){
35813 panel.setRegion(this);
35815 this.panels.add(panel);
35816 el.setStyle("position", "absolute");
35817 if(!panel.background){
35818 this.setActivePanel(panel);
35819 if(this.config.initialSize && this.panels.getCount()==1){
35820 this.resizeTo(this.config.initialSize);
35823 this.fireEvent("paneladded", this, panel);
35828 * Returns true if the panel is in this region.
35829 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35830 * @return {Boolean}
35832 hasPanel : function(panel){
35833 if(typeof panel == "object"){ // must be panel obj
35834 panel = panel.getId();
35836 return this.getPanel(panel) ? true : false;
35840 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35841 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35842 * @param {Boolean} preservePanel Overrides the config preservePanel option
35843 * @return {Roo.ContentPanel} The panel that was removed
35845 remove : function(panel, preservePanel){
35846 panel = this.getPanel(panel);
35851 this.fireEvent("beforeremove", this, panel, e);
35852 if(e.cancel === true){
35855 var panelId = panel.getId();
35856 this.panels.removeKey(panelId);
35861 * Returns the panel specified or null if it's not in this region.
35862 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35863 * @return {Roo.ContentPanel}
35865 getPanel : function(id){
35866 if(typeof id == "object"){ // must be panel obj
35869 return this.panels.get(id);
35873 * Returns this regions position (north/south/east/west/center).
35876 getPosition: function(){
35877 return this.position;
35881 * Ext JS Library 1.1.1
35882 * Copyright(c) 2006-2007, Ext JS, LLC.
35884 * Originally Released Under LGPL - original licence link has changed is not relivant.
35887 * <script type="text/javascript">
35891 * @class Roo.bootstrap.layout.Region
35892 * @extends Roo.bootstrap.layout.Basic
35893 * This class represents a region in a layout manager.
35895 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35896 * @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})
35897 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35898 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35899 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35900 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35901 * @cfg {String} title The title for the region (overrides panel titles)
35902 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35903 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35904 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35905 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35906 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35907 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35908 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35909 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35910 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35911 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35913 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35914 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35915 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35916 * @cfg {Number} width For East/West panels
35917 * @cfg {Number} height For North/South panels
35918 * @cfg {Boolean} split To show the splitter
35919 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35921 * @cfg {string} cls Extra CSS classes to add to region
35923 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35924 * @cfg {string} region the region that it inhabits..
35927 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35928 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35930 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35931 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35932 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35934 Roo.bootstrap.layout.Region = function(config)
35936 this.applyConfig(config);
35938 var mgr = config.mgr;
35939 var pos = config.region;
35940 config.skipConfig = true;
35941 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35944 this.onRender(mgr.el);
35947 this.visible = true;
35948 this.collapsed = false;
35949 this.unrendered_panels = [];
35952 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35954 position: '', // set by wrapper (eg. north/south etc..)
35955 unrendered_panels : null, // unrendered panels.
35956 createBody : function(){
35957 /** This region's body element
35958 * @type Roo.Element */
35959 this.bodyEl = this.el.createChild({
35961 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35965 onRender: function(ctr, pos)
35967 var dh = Roo.DomHelper;
35968 /** This region's container element
35969 * @type Roo.Element */
35970 this.el = dh.append(ctr.dom, {
35972 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35974 /** This region's title element
35975 * @type Roo.Element */
35977 this.titleEl = dh.append(this.el.dom,
35980 unselectable: "on",
35981 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35983 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35984 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35987 this.titleEl.enableDisplayMode();
35988 /** This region's title text element
35989 * @type HTMLElement */
35990 this.titleTextEl = this.titleEl.dom.firstChild;
35991 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35993 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35994 this.closeBtn.enableDisplayMode();
35995 this.closeBtn.on("click", this.closeClicked, this);
35996 this.closeBtn.hide();
35998 this.createBody(this.config);
35999 if(this.config.hideWhenEmpty){
36001 this.on("paneladded", this.validateVisibility, this);
36002 this.on("panelremoved", this.validateVisibility, this);
36004 if(this.autoScroll){
36005 this.bodyEl.setStyle("overflow", "auto");
36007 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36009 //if(c.titlebar !== false){
36010 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36011 this.titleEl.hide();
36013 this.titleEl.show();
36014 if(this.config.title){
36015 this.titleTextEl.innerHTML = this.config.title;
36019 if(this.config.collapsed){
36020 this.collapse(true);
36022 if(this.config.hidden){
36026 if (this.unrendered_panels && this.unrendered_panels.length) {
36027 for (var i =0;i< this.unrendered_panels.length; i++) {
36028 this.add(this.unrendered_panels[i]);
36030 this.unrendered_panels = null;
36036 applyConfig : function(c)
36039 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36040 var dh = Roo.DomHelper;
36041 if(c.titlebar !== false){
36042 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36043 this.collapseBtn.on("click", this.collapse, this);
36044 this.collapseBtn.enableDisplayMode();
36046 if(c.showPin === true || this.showPin){
36047 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36048 this.stickBtn.enableDisplayMode();
36049 this.stickBtn.on("click", this.expand, this);
36050 this.stickBtn.hide();
36055 /** This region's collapsed element
36056 * @type Roo.Element */
36059 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36060 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36063 if(c.floatable !== false){
36064 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36065 this.collapsedEl.on("click", this.collapseClick, this);
36068 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36069 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36070 id: "message", unselectable: "on", style:{"float":"left"}});
36071 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36073 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36074 this.expandBtn.on("click", this.expand, this);
36078 if(this.collapseBtn){
36079 this.collapseBtn.setVisible(c.collapsible == true);
36082 this.cmargins = c.cmargins || this.cmargins ||
36083 (this.position == "west" || this.position == "east" ?
36084 {top: 0, left: 2, right:2, bottom: 0} :
36085 {top: 2, left: 0, right:0, bottom: 2});
36087 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36090 this.bottomTabs = c.tabPosition != "top";
36092 this.autoScroll = c.autoScroll || false;
36097 this.duration = c.duration || .30;
36098 this.slideDuration = c.slideDuration || .45;
36103 * Returns true if this region is currently visible.
36104 * @return {Boolean}
36106 isVisible : function(){
36107 return this.visible;
36111 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36112 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36114 //setCollapsedTitle : function(title){
36115 // title = title || " ";
36116 // if(this.collapsedTitleTextEl){
36117 // this.collapsedTitleTextEl.innerHTML = title;
36121 getBox : function(){
36123 // if(!this.collapsed){
36124 b = this.el.getBox(false, true);
36126 // b = this.collapsedEl.getBox(false, true);
36131 getMargins : function(){
36132 return this.margins;
36133 //return this.collapsed ? this.cmargins : this.margins;
36136 highlight : function(){
36137 this.el.addClass("x-layout-panel-dragover");
36140 unhighlight : function(){
36141 this.el.removeClass("x-layout-panel-dragover");
36144 updateBox : function(box)
36146 if (!this.bodyEl) {
36147 return; // not rendered yet..
36151 if(!this.collapsed){
36152 this.el.dom.style.left = box.x + "px";
36153 this.el.dom.style.top = box.y + "px";
36154 this.updateBody(box.width, box.height);
36156 this.collapsedEl.dom.style.left = box.x + "px";
36157 this.collapsedEl.dom.style.top = box.y + "px";
36158 this.collapsedEl.setSize(box.width, box.height);
36161 this.tabs.autoSizeTabs();
36165 updateBody : function(w, h)
36168 this.el.setWidth(w);
36169 w -= this.el.getBorderWidth("rl");
36170 if(this.config.adjustments){
36171 w += this.config.adjustments[0];
36174 if(h !== null && h > 0){
36175 this.el.setHeight(h);
36176 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36177 h -= this.el.getBorderWidth("tb");
36178 if(this.config.adjustments){
36179 h += this.config.adjustments[1];
36181 this.bodyEl.setHeight(h);
36183 h = this.tabs.syncHeight(h);
36186 if(this.panelSize){
36187 w = w !== null ? w : this.panelSize.width;
36188 h = h !== null ? h : this.panelSize.height;
36190 if(this.activePanel){
36191 var el = this.activePanel.getEl();
36192 w = w !== null ? w : el.getWidth();
36193 h = h !== null ? h : el.getHeight();
36194 this.panelSize = {width: w, height: h};
36195 this.activePanel.setSize(w, h);
36197 if(Roo.isIE && this.tabs){
36198 this.tabs.el.repaint();
36203 * Returns the container element for this region.
36204 * @return {Roo.Element}
36206 getEl : function(){
36211 * Hides this region.
36214 //if(!this.collapsed){
36215 this.el.dom.style.left = "-2000px";
36218 // this.collapsedEl.dom.style.left = "-2000px";
36219 // this.collapsedEl.hide();
36221 this.visible = false;
36222 this.fireEvent("visibilitychange", this, false);
36226 * Shows this region if it was previously hidden.
36229 //if(!this.collapsed){
36232 // this.collapsedEl.show();
36234 this.visible = true;
36235 this.fireEvent("visibilitychange", this, true);
36238 closeClicked : function(){
36239 if(this.activePanel){
36240 this.remove(this.activePanel);
36244 collapseClick : function(e){
36246 e.stopPropagation();
36249 e.stopPropagation();
36255 * Collapses this region.
36256 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36259 collapse : function(skipAnim, skipCheck = false){
36260 if(this.collapsed) {
36264 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36266 this.collapsed = true;
36268 this.split.el.hide();
36270 if(this.config.animate && skipAnim !== true){
36271 this.fireEvent("invalidated", this);
36272 this.animateCollapse();
36274 this.el.setLocation(-20000,-20000);
36276 this.collapsedEl.show();
36277 this.fireEvent("collapsed", this);
36278 this.fireEvent("invalidated", this);
36284 animateCollapse : function(){
36289 * Expands this region if it was previously collapsed.
36290 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36291 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36294 expand : function(e, skipAnim){
36296 e.stopPropagation();
36298 if(!this.collapsed || this.el.hasActiveFx()) {
36302 this.afterSlideIn();
36305 this.collapsed = false;
36306 if(this.config.animate && skipAnim !== true){
36307 this.animateExpand();
36311 this.split.el.show();
36313 this.collapsedEl.setLocation(-2000,-2000);
36314 this.collapsedEl.hide();
36315 this.fireEvent("invalidated", this);
36316 this.fireEvent("expanded", this);
36320 animateExpand : function(){
36324 initTabs : function()
36326 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36328 var ts = new Roo.bootstrap.panel.Tabs({
36329 el: this.bodyEl.dom,
36330 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36331 disableTooltips: this.config.disableTabTips,
36332 toolbar : this.config.toolbar
36335 if(this.config.hideTabs){
36336 ts.stripWrap.setDisplayed(false);
36339 ts.resizeTabs = this.config.resizeTabs === true;
36340 ts.minTabWidth = this.config.minTabWidth || 40;
36341 ts.maxTabWidth = this.config.maxTabWidth || 250;
36342 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36343 ts.monitorResize = false;
36344 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36345 ts.bodyEl.addClass('roo-layout-tabs-body');
36346 this.panels.each(this.initPanelAsTab, this);
36349 initPanelAsTab : function(panel){
36350 var ti = this.tabs.addTab(
36354 this.config.closeOnTab && panel.isClosable(),
36357 if(panel.tabTip !== undefined){
36358 ti.setTooltip(panel.tabTip);
36360 ti.on("activate", function(){
36361 this.setActivePanel(panel);
36364 if(this.config.closeOnTab){
36365 ti.on("beforeclose", function(t, e){
36367 this.remove(panel);
36371 panel.tabItem = ti;
36376 updatePanelTitle : function(panel, title)
36378 if(this.activePanel == panel){
36379 this.updateTitle(title);
36382 var ti = this.tabs.getTab(panel.getEl().id);
36384 if(panel.tabTip !== undefined){
36385 ti.setTooltip(panel.tabTip);
36390 updateTitle : function(title){
36391 if(this.titleTextEl && !this.config.title){
36392 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36396 setActivePanel : function(panel)
36398 panel = this.getPanel(panel);
36399 if(this.activePanel && this.activePanel != panel){
36400 if(this.activePanel.setActiveState(false) === false){
36404 this.activePanel = panel;
36405 panel.setActiveState(true);
36406 if(this.panelSize){
36407 panel.setSize(this.panelSize.width, this.panelSize.height);
36410 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36412 this.updateTitle(panel.getTitle());
36414 this.fireEvent("invalidated", this);
36416 this.fireEvent("panelactivated", this, panel);
36420 * Shows the specified panel.
36421 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36422 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36424 showPanel : function(panel)
36426 panel = this.getPanel(panel);
36429 var tab = this.tabs.getTab(panel.getEl().id);
36430 if(tab.isHidden()){
36431 this.tabs.unhideTab(tab.id);
36435 this.setActivePanel(panel);
36442 * Get the active panel for this region.
36443 * @return {Roo.ContentPanel} The active panel or null
36445 getActivePanel : function(){
36446 return this.activePanel;
36449 validateVisibility : function(){
36450 if(this.panels.getCount() < 1){
36451 this.updateTitle(" ");
36452 this.closeBtn.hide();
36455 if(!this.isVisible()){
36462 * Adds the passed ContentPanel(s) to this region.
36463 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36464 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36466 add : function(panel)
36468 if(arguments.length > 1){
36469 for(var i = 0, len = arguments.length; i < len; i++) {
36470 this.add(arguments[i]);
36475 // if we have not been rendered yet, then we can not really do much of this..
36476 if (!this.bodyEl) {
36477 this.unrendered_panels.push(panel);
36484 if(this.hasPanel(panel)){
36485 this.showPanel(panel);
36488 panel.setRegion(this);
36489 this.panels.add(panel);
36490 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36491 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36492 // and hide them... ???
36493 this.bodyEl.dom.appendChild(panel.getEl().dom);
36494 if(panel.background !== true){
36495 this.setActivePanel(panel);
36497 this.fireEvent("paneladded", this, panel);
36504 this.initPanelAsTab(panel);
36508 if(panel.background !== true){
36509 this.tabs.activate(panel.getEl().id);
36511 this.fireEvent("paneladded", this, panel);
36516 * Hides the tab for the specified panel.
36517 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36519 hidePanel : function(panel){
36520 if(this.tabs && (panel = this.getPanel(panel))){
36521 this.tabs.hideTab(panel.getEl().id);
36526 * Unhides the tab for a previously hidden panel.
36527 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36529 unhidePanel : function(panel){
36530 if(this.tabs && (panel = this.getPanel(panel))){
36531 this.tabs.unhideTab(panel.getEl().id);
36535 clearPanels : function(){
36536 while(this.panels.getCount() > 0){
36537 this.remove(this.panels.first());
36542 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36543 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36544 * @param {Boolean} preservePanel Overrides the config preservePanel option
36545 * @return {Roo.ContentPanel} The panel that was removed
36547 remove : function(panel, preservePanel)
36549 panel = this.getPanel(panel);
36554 this.fireEvent("beforeremove", this, panel, e);
36555 if(e.cancel === true){
36558 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36559 var panelId = panel.getId();
36560 this.panels.removeKey(panelId);
36562 document.body.appendChild(panel.getEl().dom);
36565 this.tabs.removeTab(panel.getEl().id);
36566 }else if (!preservePanel){
36567 this.bodyEl.dom.removeChild(panel.getEl().dom);
36569 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36570 var p = this.panels.first();
36571 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36572 tempEl.appendChild(p.getEl().dom);
36573 this.bodyEl.update("");
36574 this.bodyEl.dom.appendChild(p.getEl().dom);
36576 this.updateTitle(p.getTitle());
36578 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36579 this.setActivePanel(p);
36581 panel.setRegion(null);
36582 if(this.activePanel == panel){
36583 this.activePanel = null;
36585 if(this.config.autoDestroy !== false && preservePanel !== true){
36586 try{panel.destroy();}catch(e){}
36588 this.fireEvent("panelremoved", this, panel);
36593 * Returns the TabPanel component used by this region
36594 * @return {Roo.TabPanel}
36596 getTabs : function(){
36600 createTool : function(parentEl, className){
36601 var btn = Roo.DomHelper.append(parentEl, {
36603 cls: "x-layout-tools-button",
36606 cls: "roo-layout-tools-button-inner " + className,
36610 btn.addClassOnOver("roo-layout-tools-button-over");
36615 * Ext JS Library 1.1.1
36616 * Copyright(c) 2006-2007, Ext JS, LLC.
36618 * Originally Released Under LGPL - original licence link has changed is not relivant.
36621 * <script type="text/javascript">
36627 * @class Roo.SplitLayoutRegion
36628 * @extends Roo.LayoutRegion
36629 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36631 Roo.bootstrap.layout.Split = function(config){
36632 this.cursor = config.cursor;
36633 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36636 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36638 splitTip : "Drag to resize.",
36639 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36640 useSplitTips : false,
36642 applyConfig : function(config){
36643 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36646 onRender : function(ctr,pos) {
36648 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36649 if(!this.config.split){
36654 var splitEl = Roo.DomHelper.append(ctr.dom, {
36656 id: this.el.id + "-split",
36657 cls: "roo-layout-split roo-layout-split-"+this.position,
36660 /** The SplitBar for this region
36661 * @type Roo.SplitBar */
36662 // does not exist yet...
36663 Roo.log([this.position, this.orientation]);
36665 this.split = new Roo.bootstrap.SplitBar({
36666 dragElement : splitEl,
36667 resizingElement: this.el,
36668 orientation : this.orientation
36671 this.split.on("moved", this.onSplitMove, this);
36672 this.split.useShim = this.config.useShim === true;
36673 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36674 if(this.useSplitTips){
36675 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36677 //if(config.collapsible){
36678 // this.split.el.on("dblclick", this.collapse, this);
36681 if(typeof this.config.minSize != "undefined"){
36682 this.split.minSize = this.config.minSize;
36684 if(typeof this.config.maxSize != "undefined"){
36685 this.split.maxSize = this.config.maxSize;
36687 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36688 this.hideSplitter();
36693 getHMaxSize : function(){
36694 var cmax = this.config.maxSize || 10000;
36695 var center = this.mgr.getRegion("center");
36696 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36699 getVMaxSize : function(){
36700 var cmax = this.config.maxSize || 10000;
36701 var center = this.mgr.getRegion("center");
36702 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36705 onSplitMove : function(split, newSize){
36706 this.fireEvent("resized", this, newSize);
36710 * Returns the {@link Roo.SplitBar} for this region.
36711 * @return {Roo.SplitBar}
36713 getSplitBar : function(){
36718 this.hideSplitter();
36719 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36722 hideSplitter : function(){
36724 this.split.el.setLocation(-2000,-2000);
36725 this.split.el.hide();
36731 this.split.el.show();
36733 Roo.bootstrap.layout.Split.superclass.show.call(this);
36736 beforeSlide: function(){
36737 if(Roo.isGecko){// firefox overflow auto bug workaround
36738 this.bodyEl.clip();
36740 this.tabs.bodyEl.clip();
36742 if(this.activePanel){
36743 this.activePanel.getEl().clip();
36745 if(this.activePanel.beforeSlide){
36746 this.activePanel.beforeSlide();
36752 afterSlide : function(){
36753 if(Roo.isGecko){// firefox overflow auto bug workaround
36754 this.bodyEl.unclip();
36756 this.tabs.bodyEl.unclip();
36758 if(this.activePanel){
36759 this.activePanel.getEl().unclip();
36760 if(this.activePanel.afterSlide){
36761 this.activePanel.afterSlide();
36767 initAutoHide : function(){
36768 if(this.autoHide !== false){
36769 if(!this.autoHideHd){
36770 var st = new Roo.util.DelayedTask(this.slideIn, this);
36771 this.autoHideHd = {
36772 "mouseout": function(e){
36773 if(!e.within(this.el, true)){
36777 "mouseover" : function(e){
36783 this.el.on(this.autoHideHd);
36787 clearAutoHide : function(){
36788 if(this.autoHide !== false){
36789 this.el.un("mouseout", this.autoHideHd.mouseout);
36790 this.el.un("mouseover", this.autoHideHd.mouseover);
36794 clearMonitor : function(){
36795 Roo.get(document).un("click", this.slideInIf, this);
36798 // these names are backwards but not changed for compat
36799 slideOut : function(){
36800 if(this.isSlid || this.el.hasActiveFx()){
36803 this.isSlid = true;
36804 if(this.collapseBtn){
36805 this.collapseBtn.hide();
36807 this.closeBtnState = this.closeBtn.getStyle('display');
36808 this.closeBtn.hide();
36810 this.stickBtn.show();
36813 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36814 this.beforeSlide();
36815 this.el.setStyle("z-index", 10001);
36816 this.el.slideIn(this.getSlideAnchor(), {
36817 callback: function(){
36819 this.initAutoHide();
36820 Roo.get(document).on("click", this.slideInIf, this);
36821 this.fireEvent("slideshow", this);
36828 afterSlideIn : function(){
36829 this.clearAutoHide();
36830 this.isSlid = false;
36831 this.clearMonitor();
36832 this.el.setStyle("z-index", "");
36833 if(this.collapseBtn){
36834 this.collapseBtn.show();
36836 this.closeBtn.setStyle('display', this.closeBtnState);
36838 this.stickBtn.hide();
36840 this.fireEvent("slidehide", this);
36843 slideIn : function(cb){
36844 if(!this.isSlid || this.el.hasActiveFx()){
36848 this.isSlid = false;
36849 this.beforeSlide();
36850 this.el.slideOut(this.getSlideAnchor(), {
36851 callback: function(){
36852 this.el.setLeftTop(-10000, -10000);
36854 this.afterSlideIn();
36862 slideInIf : function(e){
36863 if(!e.within(this.el)){
36868 animateCollapse : function(){
36869 this.beforeSlide();
36870 this.el.setStyle("z-index", 20000);
36871 var anchor = this.getSlideAnchor();
36872 this.el.slideOut(anchor, {
36873 callback : function(){
36874 this.el.setStyle("z-index", "");
36875 this.collapsedEl.slideIn(anchor, {duration:.3});
36877 this.el.setLocation(-10000,-10000);
36879 this.fireEvent("collapsed", this);
36886 animateExpand : function(){
36887 this.beforeSlide();
36888 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36889 this.el.setStyle("z-index", 20000);
36890 this.collapsedEl.hide({
36893 this.el.slideIn(this.getSlideAnchor(), {
36894 callback : function(){
36895 this.el.setStyle("z-index", "");
36898 this.split.el.show();
36900 this.fireEvent("invalidated", this);
36901 this.fireEvent("expanded", this);
36929 getAnchor : function(){
36930 return this.anchors[this.position];
36933 getCollapseAnchor : function(){
36934 return this.canchors[this.position];
36937 getSlideAnchor : function(){
36938 return this.sanchors[this.position];
36941 getAlignAdj : function(){
36942 var cm = this.cmargins;
36943 switch(this.position){
36959 getExpandAdj : function(){
36960 var c = this.collapsedEl, cm = this.cmargins;
36961 switch(this.position){
36963 return [-(cm.right+c.getWidth()+cm.left), 0];
36966 return [cm.right+c.getWidth()+cm.left, 0];
36969 return [0, -(cm.top+cm.bottom+c.getHeight())];
36972 return [0, cm.top+cm.bottom+c.getHeight()];
36978 * Ext JS Library 1.1.1
36979 * Copyright(c) 2006-2007, Ext JS, LLC.
36981 * Originally Released Under LGPL - original licence link has changed is not relivant.
36984 * <script type="text/javascript">
36987 * These classes are private internal classes
36989 Roo.bootstrap.layout.Center = function(config){
36990 config.region = "center";
36991 Roo.bootstrap.layout.Region.call(this, config);
36992 this.visible = true;
36993 this.minWidth = config.minWidth || 20;
36994 this.minHeight = config.minHeight || 20;
36997 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36999 // center panel can't be hidden
37003 // center panel can't be hidden
37006 getMinWidth: function(){
37007 return this.minWidth;
37010 getMinHeight: function(){
37011 return this.minHeight;
37024 Roo.bootstrap.layout.North = function(config)
37026 config.region = 'north';
37027 config.cursor = 'n-resize';
37029 Roo.bootstrap.layout.Split.call(this, config);
37033 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37034 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37035 this.split.el.addClass("roo-layout-split-v");
37037 var size = config.initialSize || config.height;
37038 if(typeof size != "undefined"){
37039 this.el.setHeight(size);
37042 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37044 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37048 getBox : function(){
37049 if(this.collapsed){
37050 return this.collapsedEl.getBox();
37052 var box = this.el.getBox();
37054 box.height += this.split.el.getHeight();
37059 updateBox : function(box){
37060 if(this.split && !this.collapsed){
37061 box.height -= this.split.el.getHeight();
37062 this.split.el.setLeft(box.x);
37063 this.split.el.setTop(box.y+box.height);
37064 this.split.el.setWidth(box.width);
37066 if(this.collapsed){
37067 this.updateBody(box.width, null);
37069 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37077 Roo.bootstrap.layout.South = function(config){
37078 config.region = 'south';
37079 config.cursor = 's-resize';
37080 Roo.bootstrap.layout.Split.call(this, config);
37082 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37083 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37084 this.split.el.addClass("roo-layout-split-v");
37086 var size = config.initialSize || config.height;
37087 if(typeof size != "undefined"){
37088 this.el.setHeight(size);
37092 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37093 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37094 getBox : function(){
37095 if(this.collapsed){
37096 return this.collapsedEl.getBox();
37098 var box = this.el.getBox();
37100 var sh = this.split.el.getHeight();
37107 updateBox : function(box){
37108 if(this.split && !this.collapsed){
37109 var sh = this.split.el.getHeight();
37112 this.split.el.setLeft(box.x);
37113 this.split.el.setTop(box.y-sh);
37114 this.split.el.setWidth(box.width);
37116 if(this.collapsed){
37117 this.updateBody(box.width, null);
37119 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37123 Roo.bootstrap.layout.East = function(config){
37124 config.region = "east";
37125 config.cursor = "e-resize";
37126 Roo.bootstrap.layout.Split.call(this, config);
37128 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37129 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37130 this.split.el.addClass("roo-layout-split-h");
37132 var size = config.initialSize || config.width;
37133 if(typeof size != "undefined"){
37134 this.el.setWidth(size);
37137 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37138 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37139 getBox : function(){
37140 if(this.collapsed){
37141 return this.collapsedEl.getBox();
37143 var box = this.el.getBox();
37145 var sw = this.split.el.getWidth();
37152 updateBox : function(box){
37153 if(this.split && !this.collapsed){
37154 var sw = this.split.el.getWidth();
37156 this.split.el.setLeft(box.x);
37157 this.split.el.setTop(box.y);
37158 this.split.el.setHeight(box.height);
37161 if(this.collapsed){
37162 this.updateBody(null, box.height);
37164 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37168 Roo.bootstrap.layout.West = function(config){
37169 config.region = "west";
37170 config.cursor = "w-resize";
37172 Roo.bootstrap.layout.Split.call(this, config);
37174 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37175 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37176 this.split.el.addClass("roo-layout-split-h");
37180 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37181 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37183 onRender: function(ctr, pos)
37185 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37186 var size = this.config.initialSize || this.config.width;
37187 if(typeof size != "undefined"){
37188 this.el.setWidth(size);
37192 getBox : function(){
37193 if(this.collapsed){
37194 return this.collapsedEl.getBox();
37196 var box = this.el.getBox();
37198 box.width += this.split.el.getWidth();
37203 updateBox : function(box){
37204 if(this.split && !this.collapsed){
37205 var sw = this.split.el.getWidth();
37207 this.split.el.setLeft(box.x+box.width);
37208 this.split.el.setTop(box.y);
37209 this.split.el.setHeight(box.height);
37211 if(this.collapsed){
37212 this.updateBody(null, box.height);
37214 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37217 Roo.namespace("Roo.bootstrap.panel");/*
37219 * Ext JS Library 1.1.1
37220 * Copyright(c) 2006-2007, Ext JS, LLC.
37222 * Originally Released Under LGPL - original licence link has changed is not relivant.
37225 * <script type="text/javascript">
37228 * @class Roo.ContentPanel
37229 * @extends Roo.util.Observable
37230 * A basic ContentPanel element.
37231 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37232 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37233 * @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
37234 * @cfg {Boolean} closable True if the panel can be closed/removed
37235 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37236 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37237 * @cfg {Toolbar} toolbar A toolbar for this panel
37238 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37239 * @cfg {String} title The title for this panel
37240 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37241 * @cfg {String} url Calls {@link #setUrl} with this value
37242 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37243 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37244 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37245 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37246 * @cfg {Boolean} badges render the badges
37249 * Create a new ContentPanel.
37250 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37251 * @param {String/Object} config A string to set only the title or a config object
37252 * @param {String} content (optional) Set the HTML content for this panel
37253 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37255 Roo.bootstrap.panel.Content = function( config){
37257 this.tpl = config.tpl || false;
37259 var el = config.el;
37260 var content = config.content;
37262 if(config.autoCreate){ // xtype is available if this is called from factory
37265 this.el = Roo.get(el);
37266 if(!this.el && config && config.autoCreate){
37267 if(typeof config.autoCreate == "object"){
37268 if(!config.autoCreate.id){
37269 config.autoCreate.id = config.id||el;
37271 this.el = Roo.DomHelper.append(document.body,
37272 config.autoCreate, true);
37274 var elcfg = { tag: "div",
37275 cls: "roo-layout-inactive-content",
37279 elcfg.html = config.html;
37283 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37286 this.closable = false;
37287 this.loaded = false;
37288 this.active = false;
37291 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37293 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37295 this.wrapEl = this.el; //this.el.wrap();
37297 if (config.toolbar.items) {
37298 ti = config.toolbar.items ;
37299 delete config.toolbar.items ;
37303 this.toolbar.render(this.wrapEl, 'before');
37304 for(var i =0;i < ti.length;i++) {
37305 // Roo.log(['add child', items[i]]);
37306 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37308 this.toolbar.items = nitems;
37309 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37310 delete config.toolbar;
37314 // xtype created footer. - not sure if will work as we normally have to render first..
37315 if (this.footer && !this.footer.el && this.footer.xtype) {
37316 if (!this.wrapEl) {
37317 this.wrapEl = this.el.wrap();
37320 this.footer.container = this.wrapEl.createChild();
37322 this.footer = Roo.factory(this.footer, Roo);
37327 if(typeof config == "string"){
37328 this.title = config;
37330 Roo.apply(this, config);
37334 this.resizeEl = Roo.get(this.resizeEl, true);
37336 this.resizeEl = this.el;
37338 // handle view.xtype
37346 * Fires when this panel is activated.
37347 * @param {Roo.ContentPanel} this
37351 * @event deactivate
37352 * Fires when this panel is activated.
37353 * @param {Roo.ContentPanel} this
37355 "deactivate" : true,
37359 * Fires when this panel is resized if fitToFrame is true.
37360 * @param {Roo.ContentPanel} this
37361 * @param {Number} width The width after any component adjustments
37362 * @param {Number} height The height after any component adjustments
37368 * Fires when this tab is created
37369 * @param {Roo.ContentPanel} this
37380 if(this.autoScroll){
37381 this.resizeEl.setStyle("overflow", "auto");
37383 // fix randome scrolling
37384 //this.el.on('scroll', function() {
37385 // Roo.log('fix random scolling');
37386 // this.scrollTo('top',0);
37389 content = content || this.content;
37391 this.setContent(content);
37393 if(config && config.url){
37394 this.setUrl(this.url, this.params, this.loadOnce);
37399 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37401 if (this.view && typeof(this.view.xtype) != 'undefined') {
37402 this.view.el = this.el.appendChild(document.createElement("div"));
37403 this.view = Roo.factory(this.view);
37404 this.view.render && this.view.render(false, '');
37408 this.fireEvent('render', this);
37411 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37415 setRegion : function(region){
37416 this.region = region;
37417 this.setActiveClass(region && !this.background);
37421 setActiveClass: function(state)
37424 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37425 this.el.setStyle('position','relative');
37427 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37428 this.el.setStyle('position', 'absolute');
37433 * Returns the toolbar for this Panel if one was configured.
37434 * @return {Roo.Toolbar}
37436 getToolbar : function(){
37437 return this.toolbar;
37440 setActiveState : function(active)
37442 this.active = active;
37443 this.setActiveClass(active);
37445 if(this.fireEvent("deactivate", this) === false){
37450 this.fireEvent("activate", this);
37454 * Updates this panel's element
37455 * @param {String} content The new content
37456 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37458 setContent : function(content, loadScripts){
37459 this.el.update(content, loadScripts);
37462 ignoreResize : function(w, h){
37463 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37466 this.lastSize = {width: w, height: h};
37471 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37472 * @return {Roo.UpdateManager} The UpdateManager
37474 getUpdateManager : function(){
37475 return this.el.getUpdateManager();
37478 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37479 * @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:
37482 url: "your-url.php",
37483 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37484 callback: yourFunction,
37485 scope: yourObject, //(optional scope)
37488 text: "Loading...",
37493 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37494 * 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.
37495 * @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}
37496 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37497 * @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.
37498 * @return {Roo.ContentPanel} this
37501 var um = this.el.getUpdateManager();
37502 um.update.apply(um, arguments);
37508 * 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.
37509 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37510 * @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)
37511 * @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)
37512 * @return {Roo.UpdateManager} The UpdateManager
37514 setUrl : function(url, params, loadOnce){
37515 if(this.refreshDelegate){
37516 this.removeListener("activate", this.refreshDelegate);
37518 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37519 this.on("activate", this.refreshDelegate);
37520 return this.el.getUpdateManager();
37523 _handleRefresh : function(url, params, loadOnce){
37524 if(!loadOnce || !this.loaded){
37525 var updater = this.el.getUpdateManager();
37526 updater.update(url, params, this._setLoaded.createDelegate(this));
37530 _setLoaded : function(){
37531 this.loaded = true;
37535 * Returns this panel's id
37538 getId : function(){
37543 * Returns this panel's element - used by regiosn to add.
37544 * @return {Roo.Element}
37546 getEl : function(){
37547 return this.wrapEl || this.el;
37552 adjustForComponents : function(width, height)
37554 //Roo.log('adjustForComponents ');
37555 if(this.resizeEl != this.el){
37556 width -= this.el.getFrameWidth('lr');
37557 height -= this.el.getFrameWidth('tb');
37560 var te = this.toolbar.getEl();
37561 te.setWidth(width);
37562 height -= te.getHeight();
37565 var te = this.footer.getEl();
37566 te.setWidth(width);
37567 height -= te.getHeight();
37571 if(this.adjustments){
37572 width += this.adjustments[0];
37573 height += this.adjustments[1];
37575 return {"width": width, "height": height};
37578 setSize : function(width, height){
37579 if(this.fitToFrame && !this.ignoreResize(width, height)){
37580 if(this.fitContainer && this.resizeEl != this.el){
37581 this.el.setSize(width, height);
37583 var size = this.adjustForComponents(width, height);
37584 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37585 this.fireEvent('resize', this, size.width, size.height);
37590 * Returns this panel's title
37593 getTitle : function(){
37595 if (typeof(this.title) != 'object') {
37600 for (var k in this.title) {
37601 if (!this.title.hasOwnProperty(k)) {
37605 if (k.indexOf('-') >= 0) {
37606 var s = k.split('-');
37607 for (var i = 0; i<s.length; i++) {
37608 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37611 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37618 * Set this panel's title
37619 * @param {String} title
37621 setTitle : function(title){
37622 this.title = title;
37624 this.region.updatePanelTitle(this, title);
37629 * Returns true is this panel was configured to be closable
37630 * @return {Boolean}
37632 isClosable : function(){
37633 return this.closable;
37636 beforeSlide : function(){
37638 this.resizeEl.clip();
37641 afterSlide : function(){
37643 this.resizeEl.unclip();
37647 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37648 * Will fail silently if the {@link #setUrl} method has not been called.
37649 * This does not activate the panel, just updates its content.
37651 refresh : function(){
37652 if(this.refreshDelegate){
37653 this.loaded = false;
37654 this.refreshDelegate();
37659 * Destroys this panel
37661 destroy : function(){
37662 this.el.removeAllListeners();
37663 var tempEl = document.createElement("span");
37664 tempEl.appendChild(this.el.dom);
37665 tempEl.innerHTML = "";
37671 * form - if the content panel contains a form - this is a reference to it.
37672 * @type {Roo.form.Form}
37676 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37677 * This contains a reference to it.
37683 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37693 * @param {Object} cfg Xtype definition of item to add.
37697 getChildContainer: function () {
37698 return this.getEl();
37703 var ret = new Roo.factory(cfg);
37708 if (cfg.xtype.match(/^Form$/)) {
37711 //if (this.footer) {
37712 // el = this.footer.container.insertSibling(false, 'before');
37714 el = this.el.createChild();
37717 this.form = new Roo.form.Form(cfg);
37720 if ( this.form.allItems.length) {
37721 this.form.render(el.dom);
37725 // should only have one of theses..
37726 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37727 // views.. should not be just added - used named prop 'view''
37729 cfg.el = this.el.appendChild(document.createElement("div"));
37732 var ret = new Roo.factory(cfg);
37734 ret.render && ret.render(false, ''); // render blank..
37744 * @class Roo.bootstrap.panel.Grid
37745 * @extends Roo.bootstrap.panel.Content
37747 * Create a new GridPanel.
37748 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37749 * @param {Object} config A the config object
37755 Roo.bootstrap.panel.Grid = function(config)
37759 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37760 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37762 config.el = this.wrapper;
37763 //this.el = this.wrapper;
37765 if (config.container) {
37766 // ctor'ed from a Border/panel.grid
37769 this.wrapper.setStyle("overflow", "hidden");
37770 this.wrapper.addClass('roo-grid-container');
37775 if(config.toolbar){
37776 var tool_el = this.wrapper.createChild();
37777 this.toolbar = Roo.factory(config.toolbar);
37779 if (config.toolbar.items) {
37780 ti = config.toolbar.items ;
37781 delete config.toolbar.items ;
37785 this.toolbar.render(tool_el);
37786 for(var i =0;i < ti.length;i++) {
37787 // Roo.log(['add child', items[i]]);
37788 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37790 this.toolbar.items = nitems;
37792 delete config.toolbar;
37795 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37796 config.grid.scrollBody = true;;
37797 config.grid.monitorWindowResize = false; // turn off autosizing
37798 config.grid.autoHeight = false;
37799 config.grid.autoWidth = false;
37801 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37803 if (config.background) {
37804 // render grid on panel activation (if panel background)
37805 this.on('activate', function(gp) {
37806 if (!gp.grid.rendered) {
37807 gp.grid.render(this.wrapper);
37808 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37813 this.grid.render(this.wrapper);
37814 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37817 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37818 // ??? needed ??? config.el = this.wrapper;
37823 // xtype created footer. - not sure if will work as we normally have to render first..
37824 if (this.footer && !this.footer.el && this.footer.xtype) {
37826 var ctr = this.grid.getView().getFooterPanel(true);
37827 this.footer.dataSource = this.grid.dataSource;
37828 this.footer = Roo.factory(this.footer, Roo);
37829 this.footer.render(ctr);
37839 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37840 getId : function(){
37841 return this.grid.id;
37845 * Returns the grid for this panel
37846 * @return {Roo.bootstrap.Table}
37848 getGrid : function(){
37852 setSize : function(width, height){
37853 if(!this.ignoreResize(width, height)){
37854 var grid = this.grid;
37855 var size = this.adjustForComponents(width, height);
37856 var gridel = grid.getGridEl();
37857 gridel.setSize(size.width, size.height);
37859 var thd = grid.getGridEl().select('thead',true).first();
37860 var tbd = grid.getGridEl().select('tbody', true).first();
37862 tbd.setSize(width, height - thd.getHeight());
37871 beforeSlide : function(){
37872 this.grid.getView().scroller.clip();
37875 afterSlide : function(){
37876 this.grid.getView().scroller.unclip();
37879 destroy : function(){
37880 this.grid.destroy();
37882 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37887 * @class Roo.bootstrap.panel.Nest
37888 * @extends Roo.bootstrap.panel.Content
37890 * Create a new Panel, that can contain a layout.Border.
37893 * @param {Roo.BorderLayout} layout The layout for this panel
37894 * @param {String/Object} config A string to set only the title or a config object
37896 Roo.bootstrap.panel.Nest = function(config)
37898 // construct with only one argument..
37899 /* FIXME - implement nicer consturctors
37900 if (layout.layout) {
37902 layout = config.layout;
37903 delete config.layout;
37905 if (layout.xtype && !layout.getEl) {
37906 // then layout needs constructing..
37907 layout = Roo.factory(layout, Roo);
37911 config.el = config.layout.getEl();
37913 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37915 config.layout.monitorWindowResize = false; // turn off autosizing
37916 this.layout = config.layout;
37917 this.layout.getEl().addClass("roo-layout-nested-layout");
37924 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37926 setSize : function(width, height){
37927 if(!this.ignoreResize(width, height)){
37928 var size = this.adjustForComponents(width, height);
37929 var el = this.layout.getEl();
37930 if (size.height < 1) {
37931 el.setWidth(size.width);
37933 el.setSize(size.width, size.height);
37935 var touch = el.dom.offsetWidth;
37936 this.layout.layout();
37937 // ie requires a double layout on the first pass
37938 if(Roo.isIE && !this.initialized){
37939 this.initialized = true;
37940 this.layout.layout();
37945 // activate all subpanels if not currently active..
37947 setActiveState : function(active){
37948 this.active = active;
37949 this.setActiveClass(active);
37952 this.fireEvent("deactivate", this);
37956 this.fireEvent("activate", this);
37957 // not sure if this should happen before or after..
37958 if (!this.layout) {
37959 return; // should not happen..
37962 for (var r in this.layout.regions) {
37963 reg = this.layout.getRegion(r);
37964 if (reg.getActivePanel()) {
37965 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37966 reg.setActivePanel(reg.getActivePanel());
37969 if (!reg.panels.length) {
37972 reg.showPanel(reg.getPanel(0));
37981 * Returns the nested BorderLayout for this panel
37982 * @return {Roo.BorderLayout}
37984 getLayout : function(){
37985 return this.layout;
37989 * Adds a xtype elements to the layout of the nested panel
37993 xtype : 'ContentPanel',
38000 xtype : 'NestedLayoutPanel',
38006 items : [ ... list of content panels or nested layout panels.. ]
38010 * @param {Object} cfg Xtype definition of item to add.
38012 addxtype : function(cfg) {
38013 return this.layout.addxtype(cfg);
38018 * Ext JS Library 1.1.1
38019 * Copyright(c) 2006-2007, Ext JS, LLC.
38021 * Originally Released Under LGPL - original licence link has changed is not relivant.
38024 * <script type="text/javascript">
38027 * @class Roo.TabPanel
38028 * @extends Roo.util.Observable
38029 * A lightweight tab container.
38033 // basic tabs 1, built from existing content
38034 var tabs = new Roo.TabPanel("tabs1");
38035 tabs.addTab("script", "View Script");
38036 tabs.addTab("markup", "View Markup");
38037 tabs.activate("script");
38039 // more advanced tabs, built from javascript
38040 var jtabs = new Roo.TabPanel("jtabs");
38041 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38043 // set up the UpdateManager
38044 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38045 var updater = tab2.getUpdateManager();
38046 updater.setDefaultUrl("ajax1.htm");
38047 tab2.on('activate', updater.refresh, updater, true);
38049 // Use setUrl for Ajax loading
38050 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38051 tab3.setUrl("ajax2.htm", null, true);
38054 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38057 jtabs.activate("jtabs-1");
38060 * Create a new TabPanel.
38061 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38062 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38064 Roo.bootstrap.panel.Tabs = function(config){
38066 * The container element for this TabPanel.
38067 * @type Roo.Element
38069 this.el = Roo.get(config.el);
38072 if(typeof config == "boolean"){
38073 this.tabPosition = config ? "bottom" : "top";
38075 Roo.apply(this, config);
38079 if(this.tabPosition == "bottom"){
38080 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38081 this.el.addClass("roo-tabs-bottom");
38083 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38084 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38085 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38086 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38088 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38090 if(this.tabPosition != "bottom"){
38091 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38092 * @type Roo.Element
38094 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38095 this.el.addClass("roo-tabs-top");
38099 this.bodyEl.setStyle("position", "relative");
38101 this.active = null;
38102 this.activateDelegate = this.activate.createDelegate(this);
38107 * Fires when the active tab changes
38108 * @param {Roo.TabPanel} this
38109 * @param {Roo.TabPanelItem} activePanel The new active tab
38113 * @event beforetabchange
38114 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38115 * @param {Roo.TabPanel} this
38116 * @param {Object} e Set cancel to true on this object to cancel the tab change
38117 * @param {Roo.TabPanelItem} tab The tab being changed to
38119 "beforetabchange" : true
38122 Roo.EventManager.onWindowResize(this.onResize, this);
38123 this.cpad = this.el.getPadding("lr");
38124 this.hiddenCount = 0;
38127 // toolbar on the tabbar support...
38128 if (this.toolbar) {
38129 alert("no toolbar support yet");
38130 this.toolbar = false;
38132 var tcfg = this.toolbar;
38133 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38134 this.toolbar = new Roo.Toolbar(tcfg);
38135 if (Roo.isSafari) {
38136 var tbl = tcfg.container.child('table', true);
38137 tbl.setAttribute('width', '100%');
38145 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38148 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38150 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38152 tabPosition : "top",
38154 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38156 currentTabWidth : 0,
38158 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38162 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38166 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38168 preferredTabWidth : 175,
38170 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38172 resizeTabs : false,
38174 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38176 monitorResize : true,
38178 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38183 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38184 * @param {String} id The id of the div to use <b>or create</b>
38185 * @param {String} text The text for the tab
38186 * @param {String} content (optional) Content to put in the TabPanelItem body
38187 * @param {Boolean} closable (optional) True to create a close icon on the tab
38188 * @return {Roo.TabPanelItem} The created TabPanelItem
38190 addTab : function(id, text, content, closable, tpl)
38192 var item = new Roo.bootstrap.panel.TabItem({
38196 closable : closable,
38199 this.addTabItem(item);
38201 item.setContent(content);
38207 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38208 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38209 * @return {Roo.TabPanelItem}
38211 getTab : function(id){
38212 return this.items[id];
38216 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38217 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38219 hideTab : function(id){
38220 var t = this.items[id];
38223 this.hiddenCount++;
38224 this.autoSizeTabs();
38229 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38230 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38232 unhideTab : function(id){
38233 var t = this.items[id];
38235 t.setHidden(false);
38236 this.hiddenCount--;
38237 this.autoSizeTabs();
38242 * Adds an existing {@link Roo.TabPanelItem}.
38243 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38245 addTabItem : function(item)
38247 this.items[item.id] = item;
38248 this.items.push(item);
38249 this.autoSizeTabs();
38250 // if(this.resizeTabs){
38251 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38252 // this.autoSizeTabs();
38254 // item.autoSize();
38259 * Removes a {@link Roo.TabPanelItem}.
38260 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38262 removeTab : function(id){
38263 var items = this.items;
38264 var tab = items[id];
38265 if(!tab) { return; }
38266 var index = items.indexOf(tab);
38267 if(this.active == tab && items.length > 1){
38268 var newTab = this.getNextAvailable(index);
38273 this.stripEl.dom.removeChild(tab.pnode.dom);
38274 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38275 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38277 items.splice(index, 1);
38278 delete this.items[tab.id];
38279 tab.fireEvent("close", tab);
38280 tab.purgeListeners();
38281 this.autoSizeTabs();
38284 getNextAvailable : function(start){
38285 var items = this.items;
38287 // look for a next tab that will slide over to
38288 // replace the one being removed
38289 while(index < items.length){
38290 var item = items[++index];
38291 if(item && !item.isHidden()){
38295 // if one isn't found select the previous tab (on the left)
38298 var item = items[--index];
38299 if(item && !item.isHidden()){
38307 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38308 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38310 disableTab : function(id){
38311 var tab = this.items[id];
38312 if(tab && this.active != tab){
38318 * Enables a {@link Roo.TabPanelItem} that is disabled.
38319 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38321 enableTab : function(id){
38322 var tab = this.items[id];
38327 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38328 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38329 * @return {Roo.TabPanelItem} The TabPanelItem.
38331 activate : function(id)
38333 var tab = this.items[id];
38337 if(tab == this.active || tab.disabled){
38341 this.fireEvent("beforetabchange", this, e, tab);
38342 if(e.cancel !== true && !tab.disabled){
38344 this.active.hide();
38346 this.active = this.items[id];
38347 this.active.show();
38348 this.fireEvent("tabchange", this, this.active);
38354 * Gets the active {@link Roo.TabPanelItem}.
38355 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38357 getActiveTab : function(){
38358 return this.active;
38362 * Updates the tab body element to fit the height of the container element
38363 * for overflow scrolling
38364 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38366 syncHeight : function(targetHeight){
38367 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38368 var bm = this.bodyEl.getMargins();
38369 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38370 this.bodyEl.setHeight(newHeight);
38374 onResize : function(){
38375 if(this.monitorResize){
38376 this.autoSizeTabs();
38381 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38383 beginUpdate : function(){
38384 this.updating = true;
38388 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38390 endUpdate : function(){
38391 this.updating = false;
38392 this.autoSizeTabs();
38396 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38398 autoSizeTabs : function()
38400 var count = this.items.length;
38401 var vcount = count - this.hiddenCount;
38404 this.stripEl.hide();
38406 this.stripEl.show();
38409 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38414 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38415 var availWidth = Math.floor(w / vcount);
38416 var b = this.stripBody;
38417 if(b.getWidth() > w){
38418 var tabs = this.items;
38419 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38420 if(availWidth < this.minTabWidth){
38421 /*if(!this.sleft){ // incomplete scrolling code
38422 this.createScrollButtons();
38425 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38428 if(this.currentTabWidth < this.preferredTabWidth){
38429 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38435 * Returns the number of tabs in this TabPanel.
38438 getCount : function(){
38439 return this.items.length;
38443 * Resizes all the tabs to the passed width
38444 * @param {Number} The new width
38446 setTabWidth : function(width){
38447 this.currentTabWidth = width;
38448 for(var i = 0, len = this.items.length; i < len; i++) {
38449 if(!this.items[i].isHidden()) {
38450 this.items[i].setWidth(width);
38456 * Destroys this TabPanel
38457 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38459 destroy : function(removeEl){
38460 Roo.EventManager.removeResizeListener(this.onResize, this);
38461 for(var i = 0, len = this.items.length; i < len; i++){
38462 this.items[i].purgeListeners();
38464 if(removeEl === true){
38465 this.el.update("");
38470 createStrip : function(container)
38472 var strip = document.createElement("nav");
38473 strip.className = Roo.bootstrap.version == 4 ?
38474 "navbar-light bg-light" :
38475 "navbar navbar-default"; //"x-tabs-wrap";
38476 container.appendChild(strip);
38480 createStripList : function(strip)
38482 // div wrapper for retard IE
38483 // returns the "tr" element.
38484 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38485 //'<div class="x-tabs-strip-wrap">'+
38486 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38487 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38488 return strip.firstChild; //.firstChild.firstChild.firstChild;
38490 createBody : function(container)
38492 var body = document.createElement("div");
38493 Roo.id(body, "tab-body");
38494 //Roo.fly(body).addClass("x-tabs-body");
38495 Roo.fly(body).addClass("tab-content");
38496 container.appendChild(body);
38499 createItemBody :function(bodyEl, id){
38500 var body = Roo.getDom(id);
38502 body = document.createElement("div");
38505 //Roo.fly(body).addClass("x-tabs-item-body");
38506 Roo.fly(body).addClass("tab-pane");
38507 bodyEl.insertBefore(body, bodyEl.firstChild);
38511 createStripElements : function(stripEl, text, closable, tpl)
38513 var td = document.createElement("li"); // was td..
38514 td.className = 'nav-item';
38516 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38519 stripEl.appendChild(td);
38521 td.className = "x-tabs-closable";
38522 if(!this.closeTpl){
38523 this.closeTpl = new Roo.Template(
38524 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38525 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38526 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38529 var el = this.closeTpl.overwrite(td, {"text": text});
38530 var close = el.getElementsByTagName("div")[0];
38531 var inner = el.getElementsByTagName("em")[0];
38532 return {"el": el, "close": close, "inner": inner};
38535 // not sure what this is..
38536 // if(!this.tabTpl){
38537 //this.tabTpl = new Roo.Template(
38538 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38539 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38541 // this.tabTpl = new Roo.Template(
38542 // '<a href="#">' +
38543 // '<span unselectable="on"' +
38544 // (this.disableTooltips ? '' : ' title="{text}"') +
38545 // ' >{text}</span></a>'
38551 var template = tpl || this.tabTpl || false;
38554 template = new Roo.Template(
38555 Roo.bootstrap.version == 4 ?
38557 '<a class="nav-link" href="#" unselectable="on"' +
38558 (this.disableTooltips ? '' : ' title="{text}"') +
38561 '<a class="nav-link" href="#">' +
38562 '<span unselectable="on"' +
38563 (this.disableTooltips ? '' : ' title="{text}"') +
38564 ' >{text}</span></a>'
38569 switch (typeof(template)) {
38573 template = new Roo.Template(template);
38579 var el = template.overwrite(td, {"text": text});
38581 var inner = el.getElementsByTagName("span")[0];
38583 return {"el": el, "inner": inner};
38591 * @class Roo.TabPanelItem
38592 * @extends Roo.util.Observable
38593 * Represents an individual item (tab plus body) in a TabPanel.
38594 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38595 * @param {String} id The id of this TabPanelItem
38596 * @param {String} text The text for the tab of this TabPanelItem
38597 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38599 Roo.bootstrap.panel.TabItem = function(config){
38601 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38602 * @type Roo.TabPanel
38604 this.tabPanel = config.panel;
38606 * The id for this TabPanelItem
38609 this.id = config.id;
38611 this.disabled = false;
38613 this.text = config.text;
38615 this.loaded = false;
38616 this.closable = config.closable;
38619 * The body element for this TabPanelItem.
38620 * @type Roo.Element
38622 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38623 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38624 this.bodyEl.setStyle("display", "block");
38625 this.bodyEl.setStyle("zoom", "1");
38626 //this.hideAction();
38628 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38630 this.el = Roo.get(els.el);
38631 this.inner = Roo.get(els.inner, true);
38632 this.textEl = Roo.bootstrap.version == 4 ?
38633 this.el : Roo.get(this.el.dom.firstChild, true);
38635 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38636 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38639 // this.el.on("mousedown", this.onTabMouseDown, this);
38640 this.el.on("click", this.onTabClick, this);
38642 if(config.closable){
38643 var c = Roo.get(els.close, true);
38644 c.dom.title = this.closeText;
38645 c.addClassOnOver("close-over");
38646 c.on("click", this.closeClick, this);
38652 * Fires when this tab becomes the active tab.
38653 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38654 * @param {Roo.TabPanelItem} this
38658 * @event beforeclose
38659 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38660 * @param {Roo.TabPanelItem} this
38661 * @param {Object} e Set cancel to true on this object to cancel the close.
38663 "beforeclose": true,
38666 * Fires when this tab is closed.
38667 * @param {Roo.TabPanelItem} this
38671 * @event deactivate
38672 * Fires when this tab is no longer the active tab.
38673 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38674 * @param {Roo.TabPanelItem} this
38676 "deactivate" : true
38678 this.hidden = false;
38680 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38683 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38685 purgeListeners : function(){
38686 Roo.util.Observable.prototype.purgeListeners.call(this);
38687 this.el.removeAllListeners();
38690 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38693 this.status_node.addClass("active");
38696 this.tabPanel.stripWrap.repaint();
38698 this.fireEvent("activate", this.tabPanel, this);
38702 * Returns true if this tab is the active tab.
38703 * @return {Boolean}
38705 isActive : function(){
38706 return this.tabPanel.getActiveTab() == this;
38710 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38713 this.status_node.removeClass("active");
38715 this.fireEvent("deactivate", this.tabPanel, this);
38718 hideAction : function(){
38719 this.bodyEl.hide();
38720 this.bodyEl.setStyle("position", "absolute");
38721 this.bodyEl.setLeft("-20000px");
38722 this.bodyEl.setTop("-20000px");
38725 showAction : function(){
38726 this.bodyEl.setStyle("position", "relative");
38727 this.bodyEl.setTop("");
38728 this.bodyEl.setLeft("");
38729 this.bodyEl.show();
38733 * Set the tooltip for the tab.
38734 * @param {String} tooltip The tab's tooltip
38736 setTooltip : function(text){
38737 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38738 this.textEl.dom.qtip = text;
38739 this.textEl.dom.removeAttribute('title');
38741 this.textEl.dom.title = text;
38745 onTabClick : function(e){
38746 e.preventDefault();
38747 this.tabPanel.activate(this.id);
38750 onTabMouseDown : function(e){
38751 e.preventDefault();
38752 this.tabPanel.activate(this.id);
38755 getWidth : function(){
38756 return this.inner.getWidth();
38759 setWidth : function(width){
38760 var iwidth = width - this.linode.getPadding("lr");
38761 this.inner.setWidth(iwidth);
38762 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38763 this.linode.setWidth(width);
38767 * Show or hide the tab
38768 * @param {Boolean} hidden True to hide or false to show.
38770 setHidden : function(hidden){
38771 this.hidden = hidden;
38772 this.linode.setStyle("display", hidden ? "none" : "");
38776 * Returns true if this tab is "hidden"
38777 * @return {Boolean}
38779 isHidden : function(){
38780 return this.hidden;
38784 * Returns the text for this tab
38787 getText : function(){
38791 autoSize : function(){
38792 //this.el.beginMeasure();
38793 this.textEl.setWidth(1);
38795 * #2804 [new] Tabs in Roojs
38796 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38798 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38799 //this.el.endMeasure();
38803 * Sets the text for the tab (Note: this also sets the tooltip text)
38804 * @param {String} text The tab's text and tooltip
38806 setText : function(text){
38808 this.textEl.update(text);
38809 this.setTooltip(text);
38810 //if(!this.tabPanel.resizeTabs){
38811 // this.autoSize();
38815 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38817 activate : function(){
38818 this.tabPanel.activate(this.id);
38822 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38824 disable : function(){
38825 if(this.tabPanel.active != this){
38826 this.disabled = true;
38827 this.status_node.addClass("disabled");
38832 * Enables this TabPanelItem if it was previously disabled.
38834 enable : function(){
38835 this.disabled = false;
38836 this.status_node.removeClass("disabled");
38840 * Sets the content for this TabPanelItem.
38841 * @param {String} content The content
38842 * @param {Boolean} loadScripts true to look for and load scripts
38844 setContent : function(content, loadScripts){
38845 this.bodyEl.update(content, loadScripts);
38849 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38850 * @return {Roo.UpdateManager} The UpdateManager
38852 getUpdateManager : function(){
38853 return this.bodyEl.getUpdateManager();
38857 * Set a URL to be used to load the content for this TabPanelItem.
38858 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38859 * @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)
38860 * @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)
38861 * @return {Roo.UpdateManager} The UpdateManager
38863 setUrl : function(url, params, loadOnce){
38864 if(this.refreshDelegate){
38865 this.un('activate', this.refreshDelegate);
38867 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38868 this.on("activate", this.refreshDelegate);
38869 return this.bodyEl.getUpdateManager();
38873 _handleRefresh : function(url, params, loadOnce){
38874 if(!loadOnce || !this.loaded){
38875 var updater = this.bodyEl.getUpdateManager();
38876 updater.update(url, params, this._setLoaded.createDelegate(this));
38881 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38882 * Will fail silently if the setUrl method has not been called.
38883 * This does not activate the panel, just updates its content.
38885 refresh : function(){
38886 if(this.refreshDelegate){
38887 this.loaded = false;
38888 this.refreshDelegate();
38893 _setLoaded : function(){
38894 this.loaded = true;
38898 closeClick : function(e){
38901 this.fireEvent("beforeclose", this, o);
38902 if(o.cancel !== true){
38903 this.tabPanel.removeTab(this.id);
38907 * The text displayed in the tooltip for the close icon.
38910 closeText : "Close this tab"
38913 * This script refer to:
38914 * Title: International Telephone Input
38915 * Author: Jack O'Connor
38916 * Code version: v12.1.12
38917 * Availability: https://github.com/jackocnr/intl-tel-input.git
38920 Roo.bootstrap.PhoneInputData = function() {
38923 "Afghanistan (افغانستان)",
38928 "Albania (Shqipëri)",
38933 "Algeria (الجزائر)",
38958 "Antigua and Barbuda",
38968 "Armenia (Հայաստան)",
38984 "Austria (Österreich)",
38989 "Azerbaijan (Azərbaycan)",
38999 "Bahrain (البحرين)",
39004 "Bangladesh (বাংলাদেশ)",
39014 "Belarus (Беларусь)",
39019 "Belgium (België)",
39049 "Bosnia and Herzegovina (Босна и Херцеговина)",
39064 "British Indian Ocean Territory",
39069 "British Virgin Islands",
39079 "Bulgaria (България)",
39089 "Burundi (Uburundi)",
39094 "Cambodia (កម្ពុជា)",
39099 "Cameroon (Cameroun)",
39108 ["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"]
39111 "Cape Verde (Kabu Verdi)",
39116 "Caribbean Netherlands",
39127 "Central African Republic (République centrafricaine)",
39147 "Christmas Island",
39153 "Cocos (Keeling) Islands",
39164 "Comoros (جزر القمر)",
39169 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39174 "Congo (Republic) (Congo-Brazzaville)",
39194 "Croatia (Hrvatska)",
39215 "Czech Republic (Česká republika)",
39220 "Denmark (Danmark)",
39235 "Dominican Republic (República Dominicana)",
39239 ["809", "829", "849"]
39257 "Equatorial Guinea (Guinea Ecuatorial)",
39277 "Falkland Islands (Islas Malvinas)",
39282 "Faroe Islands (Føroyar)",
39303 "French Guiana (Guyane française)",
39308 "French Polynesia (Polynésie française)",
39323 "Georgia (საქართველო)",
39328 "Germany (Deutschland)",
39348 "Greenland (Kalaallit Nunaat)",
39385 "Guinea-Bissau (Guiné Bissau)",
39410 "Hungary (Magyarország)",
39415 "Iceland (Ísland)",
39435 "Iraq (العراق)",
39451 "Israel (ישראל)",
39478 "Jordan (الأردن)",
39483 "Kazakhstan (Казахстан)",
39504 "Kuwait (الكويت)",
39509 "Kyrgyzstan (Кыргызстан)",
39519 "Latvia (Latvija)",
39524 "Lebanon (لبنان)",
39539 "Libya (ليبيا)",
39549 "Lithuania (Lietuva)",
39564 "Macedonia (FYROM) (Македонија)",
39569 "Madagascar (Madagasikara)",
39599 "Marshall Islands",
39609 "Mauritania (موريتانيا)",
39614 "Mauritius (Moris)",
39635 "Moldova (Republica Moldova)",
39645 "Mongolia (Монгол)",
39650 "Montenegro (Crna Gora)",
39660 "Morocco (المغرب)",
39666 "Mozambique (Moçambique)",
39671 "Myanmar (Burma) (မြန်မာ)",
39676 "Namibia (Namibië)",
39691 "Netherlands (Nederland)",
39696 "New Caledonia (Nouvelle-Calédonie)",
39731 "North Korea (조선 민주주의 인민 공화국)",
39736 "Northern Mariana Islands",
39752 "Pakistan (پاکستان)",
39762 "Palestine (فلسطين)",
39772 "Papua New Guinea",
39814 "Réunion (La Réunion)",
39820 "Romania (România)",
39836 "Saint Barthélemy",
39847 "Saint Kitts and Nevis",
39857 "Saint Martin (Saint-Martin (partie française))",
39863 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39868 "Saint Vincent and the Grenadines",
39883 "São Tomé and Príncipe (São Tomé e Príncipe)",
39888 "Saudi Arabia (المملكة العربية السعودية)",
39893 "Senegal (Sénégal)",
39923 "Slovakia (Slovensko)",
39928 "Slovenia (Slovenija)",
39938 "Somalia (Soomaaliya)",
39948 "South Korea (대한민국)",
39953 "South Sudan (جنوب السودان)",
39963 "Sri Lanka (ශ්රී ලංකාව)",
39968 "Sudan (السودان)",
39978 "Svalbard and Jan Mayen",
39989 "Sweden (Sverige)",
39994 "Switzerland (Schweiz)",
39999 "Syria (سوريا)",
40044 "Trinidad and Tobago",
40049 "Tunisia (تونس)",
40054 "Turkey (Türkiye)",
40064 "Turks and Caicos Islands",
40074 "U.S. Virgin Islands",
40084 "Ukraine (Україна)",
40089 "United Arab Emirates (الإمارات العربية المتحدة)",
40111 "Uzbekistan (Oʻzbekiston)",
40121 "Vatican City (Città del Vaticano)",
40132 "Vietnam (Việt Nam)",
40137 "Wallis and Futuna (Wallis-et-Futuna)",
40142 "Western Sahara (الصحراء الغربية)",
40148 "Yemen (اليمن)",
40172 * This script refer to:
40173 * Title: International Telephone Input
40174 * Author: Jack O'Connor
40175 * Code version: v12.1.12
40176 * Availability: https://github.com/jackocnr/intl-tel-input.git
40180 * @class Roo.bootstrap.PhoneInput
40181 * @extends Roo.bootstrap.TriggerField
40182 * An input with International dial-code selection
40184 * @cfg {String} defaultDialCode default '+852'
40185 * @cfg {Array} preferedCountries default []
40188 * Create a new PhoneInput.
40189 * @param {Object} config Configuration options
40192 Roo.bootstrap.PhoneInput = function(config) {
40193 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40196 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40198 listWidth: undefined,
40200 selectedClass: 'active',
40202 invalidClass : "has-warning",
40204 validClass: 'has-success',
40206 allowed: '0123456789',
40211 * @cfg {String} defaultDialCode The default dial code when initializing the input
40213 defaultDialCode: '+852',
40216 * @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
40218 preferedCountries: false,
40220 getAutoCreate : function()
40222 var data = Roo.bootstrap.PhoneInputData();
40223 var align = this.labelAlign || this.parentLabelAlign();
40226 this.allCountries = [];
40227 this.dialCodeMapping = [];
40229 for (var i = 0; i < data.length; i++) {
40231 this.allCountries[i] = {
40235 priority: c[3] || 0,
40236 areaCodes: c[4] || null
40238 this.dialCodeMapping[c[2]] = {
40241 priority: c[3] || 0,
40242 areaCodes: c[4] || null
40254 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40255 maxlength: this.max_length,
40256 cls : 'form-control tel-input',
40257 autocomplete: 'new-password'
40260 var hiddenInput = {
40263 cls: 'hidden-tel-input'
40267 hiddenInput.name = this.name;
40270 if (this.disabled) {
40271 input.disabled = true;
40274 var flag_container = {
40291 cls: this.hasFeedback ? 'has-feedback' : '',
40297 cls: 'dial-code-holder',
40304 cls: 'roo-select2-container input-group',
40311 if (this.fieldLabel.length) {
40314 tooltip: 'This field is required'
40320 cls: 'control-label',
40326 html: this.fieldLabel
40329 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40335 if(this.indicatorpos == 'right') {
40336 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40343 if(align == 'left') {
40351 if(this.labelWidth > 12){
40352 label.style = "width: " + this.labelWidth + 'px';
40354 if(this.labelWidth < 13 && this.labelmd == 0){
40355 this.labelmd = this.labelWidth;
40357 if(this.labellg > 0){
40358 label.cls += ' col-lg-' + this.labellg;
40359 input.cls += ' col-lg-' + (12 - this.labellg);
40361 if(this.labelmd > 0){
40362 label.cls += ' col-md-' + this.labelmd;
40363 container.cls += ' col-md-' + (12 - this.labelmd);
40365 if(this.labelsm > 0){
40366 label.cls += ' col-sm-' + this.labelsm;
40367 container.cls += ' col-sm-' + (12 - this.labelsm);
40369 if(this.labelxs > 0){
40370 label.cls += ' col-xs-' + this.labelxs;
40371 container.cls += ' col-xs-' + (12 - this.labelxs);
40381 var settings = this;
40383 ['xs','sm','md','lg'].map(function(size){
40384 if (settings[size]) {
40385 cfg.cls += ' col-' + size + '-' + settings[size];
40389 this.store = new Roo.data.Store({
40390 proxy : new Roo.data.MemoryProxy({}),
40391 reader : new Roo.data.JsonReader({
40402 'name' : 'dialCode',
40406 'name' : 'priority',
40410 'name' : 'areaCodes',
40417 if(!this.preferedCountries) {
40418 this.preferedCountries = [
40425 var p = this.preferedCountries.reverse();
40428 for (var i = 0; i < p.length; i++) {
40429 for (var j = 0; j < this.allCountries.length; j++) {
40430 if(this.allCountries[j].iso2 == p[i]) {
40431 var t = this.allCountries[j];
40432 this.allCountries.splice(j,1);
40433 this.allCountries.unshift(t);
40439 this.store.proxy.data = {
40441 data: this.allCountries
40447 initEvents : function()
40450 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40452 this.indicator = this.indicatorEl();
40453 this.flag = this.flagEl();
40454 this.dialCodeHolder = this.dialCodeHolderEl();
40456 this.trigger = this.el.select('div.flag-box',true).first();
40457 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40462 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40463 _this.list.setWidth(lw);
40466 this.list.on('mouseover', this.onViewOver, this);
40467 this.list.on('mousemove', this.onViewMove, this);
40468 this.inputEl().on("keyup", this.onKeyUp, this);
40469 this.inputEl().on("keypress", this.onKeyPress, this);
40471 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40473 this.view = new Roo.View(this.list, this.tpl, {
40474 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40477 this.view.on('click', this.onViewClick, this);
40478 this.setValue(this.defaultDialCode);
40481 onTriggerClick : function(e)
40483 Roo.log('trigger click');
40488 if(this.isExpanded()){
40490 this.hasFocus = false;
40492 this.store.load({});
40493 this.hasFocus = true;
40498 isExpanded : function()
40500 return this.list.isVisible();
40503 collapse : function()
40505 if(!this.isExpanded()){
40509 Roo.get(document).un('mousedown', this.collapseIf, this);
40510 Roo.get(document).un('mousewheel', this.collapseIf, this);
40511 this.fireEvent('collapse', this);
40515 expand : function()
40519 if(this.isExpanded() || !this.hasFocus){
40523 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40524 this.list.setWidth(lw);
40527 this.restrictHeight();
40529 Roo.get(document).on('mousedown', this.collapseIf, this);
40530 Roo.get(document).on('mousewheel', this.collapseIf, this);
40532 this.fireEvent('expand', this);
40535 restrictHeight : function()
40537 this.list.alignTo(this.inputEl(), this.listAlign);
40538 this.list.alignTo(this.inputEl(), this.listAlign);
40541 onViewOver : function(e, t)
40543 if(this.inKeyMode){
40546 var item = this.view.findItemFromChild(t);
40549 var index = this.view.indexOf(item);
40550 this.select(index, false);
40555 onViewClick : function(view, doFocus, el, e)
40557 var index = this.view.getSelectedIndexes()[0];
40559 var r = this.store.getAt(index);
40562 this.onSelect(r, index);
40564 if(doFocus !== false && !this.blockFocus){
40565 this.inputEl().focus();
40569 onViewMove : function(e, t)
40571 this.inKeyMode = false;
40574 select : function(index, scrollIntoView)
40576 this.selectedIndex = index;
40577 this.view.select(index);
40578 if(scrollIntoView !== false){
40579 var el = this.view.getNode(index);
40581 this.list.scrollChildIntoView(el, false);
40586 createList : function()
40588 this.list = Roo.get(document.body).createChild({
40590 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40591 style: 'display:none'
40594 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40597 collapseIf : function(e)
40599 var in_combo = e.within(this.el);
40600 var in_list = e.within(this.list);
40601 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40603 if (in_combo || in_list || is_list) {
40609 onSelect : function(record, index)
40611 if(this.fireEvent('beforeselect', this, record, index) !== false){
40613 this.setFlagClass(record.data.iso2);
40614 this.setDialCode(record.data.dialCode);
40615 this.hasFocus = false;
40617 this.fireEvent('select', this, record, index);
40621 flagEl : function()
40623 var flag = this.el.select('div.flag',true).first();
40630 dialCodeHolderEl : function()
40632 var d = this.el.select('input.dial-code-holder',true).first();
40639 setDialCode : function(v)
40641 this.dialCodeHolder.dom.value = '+'+v;
40644 setFlagClass : function(n)
40646 this.flag.dom.className = 'flag '+n;
40649 getValue : function()
40651 var v = this.inputEl().getValue();
40652 if(this.dialCodeHolder) {
40653 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40658 setValue : function(v)
40660 var d = this.getDialCode(v);
40662 //invalid dial code
40663 if(v.length == 0 || !d || d.length == 0) {
40665 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40666 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40672 this.setFlagClass(this.dialCodeMapping[d].iso2);
40673 this.setDialCode(d);
40674 this.inputEl().dom.value = v.replace('+'+d,'');
40675 this.hiddenEl().dom.value = this.getValue();
40680 getDialCode : function(v)
40684 if (v.length == 0) {
40685 return this.dialCodeHolder.dom.value;
40689 if (v.charAt(0) != "+") {
40692 var numericChars = "";
40693 for (var i = 1; i < v.length; i++) {
40694 var c = v.charAt(i);
40697 if (this.dialCodeMapping[numericChars]) {
40698 dialCode = v.substr(1, i);
40700 if (numericChars.length == 4) {
40710 this.setValue(this.defaultDialCode);
40714 hiddenEl : function()
40716 return this.el.select('input.hidden-tel-input',true).first();
40719 // after setting val
40720 onKeyUp : function(e){
40721 this.setValue(this.getValue());
40724 onKeyPress : function(e){
40725 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40732 * @class Roo.bootstrap.MoneyField
40733 * @extends Roo.bootstrap.ComboBox
40734 * Bootstrap MoneyField class
40737 * Create a new MoneyField.
40738 * @param {Object} config Configuration options
40741 Roo.bootstrap.MoneyField = function(config) {
40743 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40747 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40750 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40752 allowDecimals : true,
40754 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40756 decimalSeparator : ".",
40758 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40760 decimalPrecision : 0,
40762 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40764 allowNegative : true,
40766 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40770 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40772 minValue : Number.NEGATIVE_INFINITY,
40774 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40776 maxValue : Number.MAX_VALUE,
40778 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40780 minText : "The minimum value for this field is {0}",
40782 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40784 maxText : "The maximum value for this field is {0}",
40786 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40787 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40789 nanText : "{0} is not a valid number",
40791 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40795 * @cfg {String} defaults currency of the MoneyField
40796 * value should be in lkey
40798 defaultCurrency : false,
40800 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40802 thousandsDelimiter : false,
40804 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40815 getAutoCreate : function()
40817 var align = this.labelAlign || this.parentLabelAlign();
40829 cls : 'form-control roo-money-amount-input',
40830 autocomplete: 'new-password'
40833 var hiddenInput = {
40837 cls: 'hidden-number-input'
40840 if(this.max_length) {
40841 input.maxlength = this.max_length;
40845 hiddenInput.name = this.name;
40848 if (this.disabled) {
40849 input.disabled = true;
40852 var clg = 12 - this.inputlg;
40853 var cmd = 12 - this.inputmd;
40854 var csm = 12 - this.inputsm;
40855 var cxs = 12 - this.inputxs;
40859 cls : 'row roo-money-field',
40863 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40867 cls: 'roo-select2-container input-group',
40871 cls : 'form-control roo-money-currency-input',
40872 autocomplete: 'new-password',
40874 name : this.currencyName
40878 cls : 'input-group-addon',
40892 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40896 cls: this.hasFeedback ? 'has-feedback' : '',
40907 if (this.fieldLabel.length) {
40910 tooltip: 'This field is required'
40916 cls: 'control-label',
40922 html: this.fieldLabel
40925 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40931 if(this.indicatorpos == 'right') {
40932 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40939 if(align == 'left') {
40947 if(this.labelWidth > 12){
40948 label.style = "width: " + this.labelWidth + 'px';
40950 if(this.labelWidth < 13 && this.labelmd == 0){
40951 this.labelmd = this.labelWidth;
40953 if(this.labellg > 0){
40954 label.cls += ' col-lg-' + this.labellg;
40955 input.cls += ' col-lg-' + (12 - this.labellg);
40957 if(this.labelmd > 0){
40958 label.cls += ' col-md-' + this.labelmd;
40959 container.cls += ' col-md-' + (12 - this.labelmd);
40961 if(this.labelsm > 0){
40962 label.cls += ' col-sm-' + this.labelsm;
40963 container.cls += ' col-sm-' + (12 - this.labelsm);
40965 if(this.labelxs > 0){
40966 label.cls += ' col-xs-' + this.labelxs;
40967 container.cls += ' col-xs-' + (12 - this.labelxs);
40978 var settings = this;
40980 ['xs','sm','md','lg'].map(function(size){
40981 if (settings[size]) {
40982 cfg.cls += ' col-' + size + '-' + settings[size];
40989 initEvents : function()
40991 this.indicator = this.indicatorEl();
40993 this.initCurrencyEvent();
40995 this.initNumberEvent();
40998 initCurrencyEvent : function()
41001 throw "can not find store for combo";
41004 this.store = Roo.factory(this.store, Roo.data);
41005 this.store.parent = this;
41009 this.triggerEl = this.el.select('.input-group-addon', true).first();
41011 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41016 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41017 _this.list.setWidth(lw);
41020 this.list.on('mouseover', this.onViewOver, this);
41021 this.list.on('mousemove', this.onViewMove, this);
41022 this.list.on('scroll', this.onViewScroll, this);
41025 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41028 this.view = new Roo.View(this.list, this.tpl, {
41029 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41032 this.view.on('click', this.onViewClick, this);
41034 this.store.on('beforeload', this.onBeforeLoad, this);
41035 this.store.on('load', this.onLoad, this);
41036 this.store.on('loadexception', this.onLoadException, this);
41038 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41039 "up" : function(e){
41040 this.inKeyMode = true;
41044 "down" : function(e){
41045 if(!this.isExpanded()){
41046 this.onTriggerClick();
41048 this.inKeyMode = true;
41053 "enter" : function(e){
41056 if(this.fireEvent("specialkey", this, e)){
41057 this.onViewClick(false);
41063 "esc" : function(e){
41067 "tab" : function(e){
41070 if(this.fireEvent("specialkey", this, e)){
41071 this.onViewClick(false);
41079 doRelay : function(foo, bar, hname){
41080 if(hname == 'down' || this.scope.isExpanded()){
41081 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41089 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41093 initNumberEvent : function(e)
41095 this.inputEl().on("keydown" , this.fireKey, this);
41096 this.inputEl().on("focus", this.onFocus, this);
41097 this.inputEl().on("blur", this.onBlur, this);
41099 this.inputEl().relayEvent('keyup', this);
41101 if(this.indicator){
41102 this.indicator.addClass('invisible');
41105 this.originalValue = this.getValue();
41107 if(this.validationEvent == 'keyup'){
41108 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41109 this.inputEl().on('keyup', this.filterValidation, this);
41111 else if(this.validationEvent !== false){
41112 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41115 if(this.selectOnFocus){
41116 this.on("focus", this.preFocus, this);
41119 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41120 this.inputEl().on("keypress", this.filterKeys, this);
41122 this.inputEl().relayEvent('keypress', this);
41125 var allowed = "0123456789";
41127 if(this.allowDecimals){
41128 allowed += this.decimalSeparator;
41131 if(this.allowNegative){
41135 if(this.thousandsDelimiter) {
41139 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41141 var keyPress = function(e){
41143 var k = e.getKey();
41145 var c = e.getCharCode();
41148 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41149 allowed.indexOf(String.fromCharCode(c)) === -1
41155 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41159 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41164 this.inputEl().on("keypress", keyPress, this);
41168 onTriggerClick : function(e)
41175 this.loadNext = false;
41177 if(this.isExpanded()){
41182 this.hasFocus = true;
41184 if(this.triggerAction == 'all') {
41185 this.doQuery(this.allQuery, true);
41189 this.doQuery(this.getRawValue());
41192 getCurrency : function()
41194 var v = this.currencyEl().getValue();
41199 restrictHeight : function()
41201 this.list.alignTo(this.currencyEl(), this.listAlign);
41202 this.list.alignTo(this.currencyEl(), this.listAlign);
41205 onViewClick : function(view, doFocus, el, e)
41207 var index = this.view.getSelectedIndexes()[0];
41209 var r = this.store.getAt(index);
41212 this.onSelect(r, index);
41216 onSelect : function(record, index){
41218 if(this.fireEvent('beforeselect', this, record, index) !== false){
41220 this.setFromCurrencyData(index > -1 ? record.data : false);
41224 this.fireEvent('select', this, record, index);
41228 setFromCurrencyData : function(o)
41232 this.lastCurrency = o;
41234 if (this.currencyField) {
41235 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41237 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41240 this.lastSelectionText = currency;
41242 //setting default currency
41243 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41244 this.setCurrency(this.defaultCurrency);
41248 this.setCurrency(currency);
41251 setFromData : function(o)
41255 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41257 this.setFromCurrencyData(c);
41262 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41264 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41267 this.setValue(value);
41271 setCurrency : function(v)
41273 this.currencyValue = v;
41276 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41281 setValue : function(v)
41283 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41289 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41291 this.inputEl().dom.value = (v == '') ? '' :
41292 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41294 if(!this.allowZero && v === '0') {
41295 this.hiddenEl().dom.value = '';
41296 this.inputEl().dom.value = '';
41303 getRawValue : function()
41305 var v = this.inputEl().getValue();
41310 getValue : function()
41312 return this.fixPrecision(this.parseValue(this.getRawValue()));
41315 parseValue : function(value)
41317 if(this.thousandsDelimiter) {
41319 r = new RegExp(",", "g");
41320 value = value.replace(r, "");
41323 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41324 return isNaN(value) ? '' : value;
41328 fixPrecision : function(value)
41330 if(this.thousandsDelimiter) {
41332 r = new RegExp(",", "g");
41333 value = value.replace(r, "");
41336 var nan = isNaN(value);
41338 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41339 return nan ? '' : value;
41341 return parseFloat(value).toFixed(this.decimalPrecision);
41344 decimalPrecisionFcn : function(v)
41346 return Math.floor(v);
41349 validateValue : function(value)
41351 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41355 var num = this.parseValue(value);
41358 this.markInvalid(String.format(this.nanText, value));
41362 if(num < this.minValue){
41363 this.markInvalid(String.format(this.minText, this.minValue));
41367 if(num > this.maxValue){
41368 this.markInvalid(String.format(this.maxText, this.maxValue));
41375 validate : function()
41377 if(this.disabled || this.allowBlank){
41382 var currency = this.getCurrency();
41384 if(this.validateValue(this.getRawValue()) && currency.length){
41389 this.markInvalid();
41393 getName: function()
41398 beforeBlur : function()
41404 var v = this.parseValue(this.getRawValue());
41411 onBlur : function()
41415 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41416 //this.el.removeClass(this.focusClass);
41419 this.hasFocus = false;
41421 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41425 var v = this.getValue();
41427 if(String(v) !== String(this.startValue)){
41428 this.fireEvent('change', this, v, this.startValue);
41431 this.fireEvent("blur", this);
41434 inputEl : function()
41436 return this.el.select('.roo-money-amount-input', true).first();
41439 currencyEl : function()
41441 return this.el.select('.roo-money-currency-input', true).first();
41444 hiddenEl : function()
41446 return this.el.select('input.hidden-number-input',true).first();