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 var view_height = Roo.lib.Dom.getViewportHeight(true);
2923 Roo.log("dialog height: "+this.height);
2924 Roo.log("view height:" + view_height);
2927 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2928 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
2933 if(this.max_width !== 0) {
2935 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2938 this.setSize(w, this.height);
2942 if(this.max_height) {
2943 this.setSize(w,Math.min(
2945 Roo.lib.Dom.getViewportHeight(true) - 60
2951 if(!this.fit_content) {
2952 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2956 this.setSize(w, Math.min(
2958 this.headerEl.getHeight() +
2959 this.footerEl.getHeight() +
2960 this.getChildHeight(this.bodyEl.dom.childNodes),
2961 Roo.lib.Dom.getViewportHeight(true) - 60)
2967 setSize : function(w,h)
2978 if (!this.rendered) {
2982 //this.el.setStyle('display', 'block');
2983 this.el.removeClass('hideing');
2984 this.el.dom.style.display='block';
2986 Roo.get(document.body).addClass('modal-open');
2988 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2991 this.el.addClass('show');
2992 this.el.addClass('in');
2995 this.el.addClass('show');
2996 this.el.addClass('in');
2999 // not sure how we can show data in here..
3001 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3004 Roo.get(document.body).addClass("x-body-masked");
3006 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3007 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3008 this.maskEl.dom.style.display = 'block';
3009 this.maskEl.addClass('show');
3014 this.fireEvent('show', this);
3016 // set zindex here - otherwise it appears to be ignored...
3017 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3020 this.items.forEach( function(e) {
3021 e.layout ? e.layout() : false;
3029 if(this.fireEvent("beforehide", this) !== false){
3031 this.maskEl.removeClass('show');
3033 this.maskEl.dom.style.display = '';
3034 Roo.get(document.body).removeClass("x-body-masked");
3035 this.el.removeClass('in');
3036 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3038 if(this.animate){ // why
3039 this.el.addClass('hideing');
3040 this.el.removeClass('show');
3042 if (!this.el.hasClass('hideing')) {
3043 return; // it's been shown again...
3046 this.el.dom.style.display='';
3048 Roo.get(document.body).removeClass('modal-open');
3049 this.el.removeClass('hideing');
3053 this.el.removeClass('show');
3054 this.el.dom.style.display='';
3055 Roo.get(document.body).removeClass('modal-open');
3058 this.fireEvent('hide', this);
3061 isVisible : function()
3064 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3068 addButton : function(str, cb)
3072 var b = Roo.apply({}, { html : str } );
3073 b.xns = b.xns || Roo.bootstrap;
3074 b.xtype = b.xtype || 'Button';
3075 if (typeof(b.listeners) == 'undefined') {
3076 b.listeners = { click : cb.createDelegate(this) };
3079 var btn = Roo.factory(b);
3081 btn.render(this.getButtonContainer());
3087 setDefaultButton : function(btn)
3089 //this.el.select('.modal-footer').()
3092 resizeTo: function(w,h)
3094 this.dialogEl.setWidth(w);
3096 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 30; // dialog margin-bottom: 30
3098 this.bodyEl.setHeight(h - diff);
3100 this.fireEvent('resize', this);
3103 setContentSize : function(w, h)
3107 onButtonClick: function(btn,e)
3110 this.fireEvent('btnclick', btn.name, e);
3113 * Set the title of the Dialog
3114 * @param {String} str new Title
3116 setTitle: function(str) {
3117 this.titleEl.dom.innerHTML = str;
3120 * Set the body of the Dialog
3121 * @param {String} str new Title
3123 setBody: function(str) {
3124 this.bodyEl.dom.innerHTML = str;
3127 * Set the body of the Dialog using the template
3128 * @param {Obj} data - apply this data to the template and replace the body contents.
3130 applyBody: function(obj)
3133 Roo.log("Error - using apply Body without a template");
3136 this.tmpl.overwrite(this.bodyEl, obj);
3139 getChildHeight : function(child_nodes)
3143 child_nodes.length == 0
3148 var child_height = 0;
3150 for(var i = 0; i < child_nodes.length; i++) {
3153 * for modal with tabs...
3154 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3156 var layout_childs = child_nodes[i].childNodes;
3158 for(var j = 0; j < layout_childs.length; j++) {
3160 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3162 var layout_body_childs = layout_childs[j].childNodes;
3164 for(var k = 0; k < layout_body_childs.length; k++) {
3166 if(layout_body_childs[k].classList.contains('navbar')) {
3167 child_height += layout_body_childs[k].offsetHeight;
3171 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3173 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3175 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3177 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3178 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3193 child_height += child_nodes[i].offsetHeight;
3194 // Roo.log(child_nodes[i].offsetHeight);
3197 return child_height;
3203 Roo.apply(Roo.bootstrap.Modal, {
3205 * Button config that displays a single OK button
3214 * Button config that displays Yes and No buttons
3230 * Button config that displays OK and Cancel buttons
3245 * Button config that displays Yes, No and Cancel buttons
3269 * messagebox - can be used as a replace
3273 * @class Roo.MessageBox
3274 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3278 Roo.Msg.alert('Status', 'Changes saved successfully.');
3280 // Prompt for user data:
3281 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3283 // process text value...
3287 // Show a dialog using config options:
3289 title:'Save Changes?',
3290 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3291 buttons: Roo.Msg.YESNOCANCEL,
3298 Roo.bootstrap.MessageBox = function(){
3299 var dlg, opt, mask, waitTimer;
3300 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3301 var buttons, activeTextEl, bwidth;
3305 var handleButton = function(button){
3307 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3311 var handleHide = function(){
3313 dlg.el.removeClass(opt.cls);
3316 // Roo.TaskMgr.stop(waitTimer);
3317 // waitTimer = null;
3322 var updateButtons = function(b){
3325 buttons["ok"].hide();
3326 buttons["cancel"].hide();
3327 buttons["yes"].hide();
3328 buttons["no"].hide();
3329 dlg.footerEl.hide();
3333 dlg.footerEl.show();
3334 for(var k in buttons){
3335 if(typeof buttons[k] != "function"){
3338 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3339 width += buttons[k].el.getWidth()+15;
3349 var handleEsc = function(d, k, e){
3350 if(opt && opt.closable !== false){
3360 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3361 * @return {Roo.BasicDialog} The BasicDialog element
3363 getDialog : function(){
3365 dlg = new Roo.bootstrap.Modal( {
3368 //constraintoviewport:false,
3370 //collapsible : false,
3375 //buttonAlign:"center",
3376 closeClick : function(){
3377 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3380 handleButton("cancel");
3385 dlg.on("hide", handleHide);
3387 //dlg.addKeyListener(27, handleEsc);
3389 this.buttons = buttons;
3390 var bt = this.buttonText;
3391 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3392 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3393 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3394 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3396 bodyEl = dlg.bodyEl.createChild({
3398 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3399 '<textarea class="roo-mb-textarea"></textarea>' +
3400 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3402 msgEl = bodyEl.dom.firstChild;
3403 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3404 textboxEl.enableDisplayMode();
3405 textboxEl.addKeyListener([10,13], function(){
3406 if(dlg.isVisible() && opt && opt.buttons){
3409 }else if(opt.buttons.yes){
3410 handleButton("yes");
3414 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3415 textareaEl.enableDisplayMode();
3416 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3417 progressEl.enableDisplayMode();
3419 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3420 var pf = progressEl.dom.firstChild;
3422 pp = Roo.get(pf.firstChild);
3423 pp.setHeight(pf.offsetHeight);
3431 * Updates the message box body text
3432 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3433 * the XHTML-compliant non-breaking space character '&#160;')
3434 * @return {Roo.MessageBox} This message box
3436 updateText : function(text)
3438 if(!dlg.isVisible() && !opt.width){
3439 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3440 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3442 msgEl.innerHTML = text || ' ';
3444 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3445 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3447 Math.min(opt.width || cw , this.maxWidth),
3448 Math.max(opt.minWidth || this.minWidth, bwidth)
3451 activeTextEl.setWidth(w);
3453 if(dlg.isVisible()){
3454 dlg.fixedcenter = false;
3456 // to big, make it scroll. = But as usual stupid IE does not support
3459 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3460 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3461 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3463 bodyEl.dom.style.height = '';
3464 bodyEl.dom.style.overflowY = '';
3467 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3469 bodyEl.dom.style.overflowX = '';
3472 dlg.setContentSize(w, bodyEl.getHeight());
3473 if(dlg.isVisible()){
3474 dlg.fixedcenter = true;
3480 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3481 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3482 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3483 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3484 * @return {Roo.MessageBox} This message box
3486 updateProgress : function(value, text){
3488 this.updateText(text);
3491 if (pp) { // weird bug on my firefox - for some reason this is not defined
3492 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3493 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3499 * Returns true if the message box is currently displayed
3500 * @return {Boolean} True if the message box is visible, else false
3502 isVisible : function(){
3503 return dlg && dlg.isVisible();
3507 * Hides the message box if it is displayed
3510 if(this.isVisible()){
3516 * Displays a new message box, or reinitializes an existing message box, based on the config options
3517 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3518 * The following config object properties are supported:
3520 Property Type Description
3521 ---------- --------------- ------------------------------------------------------------------------------------
3522 animEl String/Element An id or Element from which the message box should animate as it opens and
3523 closes (defaults to undefined)
3524 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3525 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3526 closable Boolean False to hide the top-right close button (defaults to true). Note that
3527 progress and wait dialogs will ignore this property and always hide the
3528 close button as they can only be closed programmatically.
3529 cls String A custom CSS class to apply to the message box element
3530 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3531 displayed (defaults to 75)
3532 fn Function A callback function to execute after closing the dialog. The arguments to the
3533 function will be btn (the name of the button that was clicked, if applicable,
3534 e.g. "ok"), and text (the value of the active text field, if applicable).
3535 Progress and wait dialogs will ignore this option since they do not respond to
3536 user actions and can only be closed programmatically, so any required function
3537 should be called by the same code after it closes the dialog.
3538 icon String A CSS class that provides a background image to be used as an icon for
3539 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3540 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3541 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3542 modal Boolean False to allow user interaction with the page while the message box is
3543 displayed (defaults to true)
3544 msg String A string that will replace the existing message box body text (defaults
3545 to the XHTML-compliant non-breaking space character ' ')
3546 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3547 progress Boolean True to display a progress bar (defaults to false)
3548 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3549 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3550 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3551 title String The title text
3552 value String The string value to set into the active textbox element if displayed
3553 wait Boolean True to display a progress bar (defaults to false)
3554 width Number The width of the dialog in pixels
3561 msg: 'Please enter your address:',
3563 buttons: Roo.MessageBox.OKCANCEL,
3566 animEl: 'addAddressBtn'
3569 * @param {Object} config Configuration options
3570 * @return {Roo.MessageBox} This message box
3572 show : function(options)
3575 // this causes nightmares if you show one dialog after another
3576 // especially on callbacks..
3578 if(this.isVisible()){
3581 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3582 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3583 Roo.log("New Dialog Message:" + options.msg )
3584 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3585 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3588 var d = this.getDialog();
3590 d.setTitle(opt.title || " ");
3591 d.closeEl.setDisplayed(opt.closable !== false);
3592 activeTextEl = textboxEl;
3593 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3598 textareaEl.setHeight(typeof opt.multiline == "number" ?
3599 opt.multiline : this.defaultTextHeight);
3600 activeTextEl = textareaEl;
3609 progressEl.setDisplayed(opt.progress === true);
3611 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3613 this.updateProgress(0);
3614 activeTextEl.dom.value = opt.value || "";
3616 dlg.setDefaultButton(activeTextEl);
3618 var bs = opt.buttons;
3622 }else if(bs && bs.yes){
3623 db = buttons["yes"];
3625 dlg.setDefaultButton(db);
3627 bwidth = updateButtons(opt.buttons);
3628 this.updateText(opt.msg);
3630 d.el.addClass(opt.cls);
3632 d.proxyDrag = opt.proxyDrag === true;
3633 d.modal = opt.modal !== false;
3634 d.mask = opt.modal !== false ? mask : false;
3636 // force it to the end of the z-index stack so it gets a cursor in FF
3637 document.body.appendChild(dlg.el.dom);
3638 d.animateTarget = null;
3639 d.show(options.animEl);
3645 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3646 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3647 * and closing the message box when the process is complete.
3648 * @param {String} title The title bar text
3649 * @param {String} msg The message box body text
3650 * @return {Roo.MessageBox} This message box
3652 progress : function(title, msg){
3659 minWidth: this.minProgressWidth,
3666 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3667 * If a callback function is passed it will be called after the user clicks the button, and the
3668 * id of the button that was clicked will be passed as the only parameter to the callback
3669 * (could also be the top-right close button).
3670 * @param {String} title The title bar text
3671 * @param {String} msg The message box body text
3672 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3673 * @param {Object} scope (optional) The scope of the callback function
3674 * @return {Roo.MessageBox} This message box
3676 alert : function(title, msg, fn, scope)
3691 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3692 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3693 * You are responsible for closing the message box when the process is complete.
3694 * @param {String} msg The message box body text
3695 * @param {String} title (optional) The title bar text
3696 * @return {Roo.MessageBox} This message box
3698 wait : function(msg, title){
3709 waitTimer = Roo.TaskMgr.start({
3711 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3719 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3720 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3721 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3722 * @param {String} title The title bar text
3723 * @param {String} msg The message box body text
3724 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3725 * @param {Object} scope (optional) The scope of the callback function
3726 * @return {Roo.MessageBox} This message box
3728 confirm : function(title, msg, fn, scope){
3732 buttons: this.YESNO,
3741 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3742 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3743 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3744 * (could also be the top-right close button) and the text that was entered will be passed as the two
3745 * parameters to the callback.
3746 * @param {String} title The title bar text
3747 * @param {String} msg The message box body text
3748 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3749 * @param {Object} scope (optional) The scope of the callback function
3750 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3751 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3752 * @return {Roo.MessageBox} This message box
3754 prompt : function(title, msg, fn, scope, multiline){
3758 buttons: this.OKCANCEL,
3763 multiline: multiline,
3770 * Button config that displays a single OK button
3775 * Button config that displays Yes and No buttons
3778 YESNO : {yes:true, no:true},
3780 * Button config that displays OK and Cancel buttons
3783 OKCANCEL : {ok:true, cancel:true},
3785 * Button config that displays Yes, No and Cancel buttons
3788 YESNOCANCEL : {yes:true, no:true, cancel:true},
3791 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3794 defaultTextHeight : 75,
3796 * The maximum width in pixels of the message box (defaults to 600)
3801 * The minimum width in pixels of the message box (defaults to 100)
3806 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3807 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3810 minProgressWidth : 250,
3812 * An object containing the default button text strings that can be overriden for localized language support.
3813 * Supported properties are: ok, cancel, yes and no.
3814 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3827 * Shorthand for {@link Roo.MessageBox}
3829 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3830 Roo.Msg = Roo.Msg || Roo.MessageBox;
3839 * @class Roo.bootstrap.Navbar
3840 * @extends Roo.bootstrap.Component
3841 * Bootstrap Navbar class
3844 * Create a new Navbar
3845 * @param {Object} config The config object
3849 Roo.bootstrap.Navbar = function(config){
3850 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3854 * @event beforetoggle
3855 * Fire before toggle the menu
3856 * @param {Roo.EventObject} e
3858 "beforetoggle" : true
3862 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3871 getAutoCreate : function(){
3874 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3878 initEvents :function ()
3880 //Roo.log(this.el.select('.navbar-toggle',true));
3881 this.el.select('.navbar-toggle',true).on('click', function() {
3882 if(this.fireEvent('beforetoggle', this) !== false){
3883 var ce = this.el.select('.navbar-collapse',true).first();
3884 ce.toggleClass('in'); // old...
3885 if (ce.hasClass('collapse')) {
3887 ce.removeClass('collapse');
3888 ce.addClass('show');
3889 var h = ce.getHeight();
3891 ce.removeClass('show');
3892 // at this point we should be able to see it..
3893 ce.addClass('collapsing');
3895 ce.setHeight(0); // resize it ...
3896 ce.on('transitionend', function() {
3897 Roo.log('done transition');
3898 ce.removeClass('collapsing');
3899 ce.addClass('show');
3900 ce.removeClass('collapse');
3902 ce.dom.style.height = '';
3903 }, this, { single: true} );
3907 ce.setHeight(ce.getHeight());
3908 ce.removeClass('show');
3909 ce.addClass('collapsing');
3911 ce.on('transitionend', function() {
3912 ce.dom.style.height = '';
3913 ce.removeClass('collapsing');
3914 ce.addClass('collapse');
3915 }, this, { single: true} );
3927 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3929 var size = this.el.getSize();
3930 this.maskEl.setSize(size.width, size.height);
3931 this.maskEl.enableDisplayMode("block");
3940 getChildContainer : function()
3942 if (this.el.select('.collapse').getCount()) {
3943 return this.el.select('.collapse',true).first();
3976 * @class Roo.bootstrap.NavSimplebar
3977 * @extends Roo.bootstrap.Navbar
3978 * Bootstrap Sidebar class
3980 * @cfg {Boolean} inverse is inverted color
3982 * @cfg {String} type (nav | pills | tabs)
3983 * @cfg {Boolean} arrangement stacked | justified
3984 * @cfg {String} align (left | right) alignment
3986 * @cfg {Boolean} main (true|false) main nav bar? default false
3987 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3989 * @cfg {String} tag (header|footer|nav|div) default is nav
3991 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
3995 * Create a new Sidebar
3996 * @param {Object} config The config object
4000 Roo.bootstrap.NavSimplebar = function(config){
4001 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4004 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4020 getAutoCreate : function(){
4024 tag : this.tag || 'div',
4025 cls : 'navbar navbar-expand-lg roo-navbar-simple'
4027 if (['light','white'].indexOf(this.weight) > -1) {
4028 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4030 cfg.cls += ' bg-' + this.weight;
4033 cfg.cls += ' navbar-inverse';
4037 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4039 //if (Roo.bootstrap.version == 4) {
4051 this.type = this.type || 'nav';
4052 if (['tabs','pills'].indexOf(this.type) != -1) {
4053 cfg.cn[0].cls += ' nav-' + this.type
4057 if (this.type!=='nav') {
4058 Roo.log('nav type must be nav/tabs/pills')
4060 cfg.cn[0].cls += ' navbar-nav'
4066 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4067 cfg.cn[0].cls += ' nav-' + this.arrangement;
4071 if (this.align === 'right') {
4072 cfg.cn[0].cls += ' navbar-right';
4097 * navbar-expand-md fixed-top
4101 * @class Roo.bootstrap.NavHeaderbar
4102 * @extends Roo.bootstrap.NavSimplebar
4103 * Bootstrap Sidebar class
4105 * @cfg {String} brand what is brand
4106 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4107 * @cfg {String} brand_href href of the brand
4108 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4109 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4110 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4111 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4114 * Create a new Sidebar
4115 * @param {Object} config The config object
4119 Roo.bootstrap.NavHeaderbar = function(config){
4120 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4124 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4131 desktopCenter : false,
4134 getAutoCreate : function(){
4137 tag: this.nav || 'nav',
4138 cls: 'navbar navbar-expand-md',
4144 if (this.desktopCenter) {
4145 cn.push({cls : 'container', cn : []});
4153 cls: 'navbar-toggle navbar-toggler',
4154 'data-toggle': 'collapse',
4159 html: 'Toggle navigation'
4163 cls: 'icon-bar navbar-toggler-icon'
4176 cn.push( Roo.bootstrap.version == 4 ? btn : {
4178 cls: 'navbar-header',
4187 cls: 'collapse navbar-collapse',
4191 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4193 if (['light','white'].indexOf(this.weight) > -1) {
4194 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4196 cfg.cls += ' bg-' + this.weight;
4199 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4200 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4202 // tag can override this..
4204 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4207 if (this.brand !== '') {
4208 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4209 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4211 href: this.brand_href ? this.brand_href : '#',
4212 cls: 'navbar-brand',
4220 cfg.cls += ' main-nav';
4228 getHeaderChildContainer : function()
4230 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4231 return this.el.select('.navbar-header',true).first();
4234 return this.getChildContainer();
4238 initEvents : function()
4240 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4242 if (this.autohide) {
4247 Roo.get(document).on('scroll',function(e) {
4248 var ns = Roo.get(document).getScroll().top;
4249 var os = prevScroll;
4253 ft.removeClass('slideDown');
4254 ft.addClass('slideUp');
4257 ft.removeClass('slideUp');
4258 ft.addClass('slideDown');
4279 * @class Roo.bootstrap.NavSidebar
4280 * @extends Roo.bootstrap.Navbar
4281 * Bootstrap Sidebar class
4284 * Create a new Sidebar
4285 * @param {Object} config The config object
4289 Roo.bootstrap.NavSidebar = function(config){
4290 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4293 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4295 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4297 getAutoCreate : function(){
4302 cls: 'sidebar sidebar-nav'
4324 * @class Roo.bootstrap.NavGroup
4325 * @extends Roo.bootstrap.Component
4326 * Bootstrap NavGroup class
4327 * @cfg {String} align (left|right)
4328 * @cfg {Boolean} inverse
4329 * @cfg {String} type (nav|pills|tab) default nav
4330 * @cfg {String} navId - reference Id for navbar.
4334 * Create a new nav group
4335 * @param {Object} config The config object
4338 Roo.bootstrap.NavGroup = function(config){
4339 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4342 Roo.bootstrap.NavGroup.register(this);
4346 * Fires when the active item changes
4347 * @param {Roo.bootstrap.NavGroup} this
4348 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4349 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4356 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4367 getAutoCreate : function()
4369 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4375 if (Roo.bootstrap.version == 4) {
4376 if (['tabs','pills'].indexOf(this.type) != -1) {
4377 cfg.cls += ' nav-' + this.type;
4379 cfg.cls += ' navbar-nav';
4382 if (['tabs','pills'].indexOf(this.type) != -1) {
4383 cfg.cls += ' nav-' + this.type
4385 if (this.type !== 'nav') {
4386 Roo.log('nav type must be nav/tabs/pills')
4388 cfg.cls += ' navbar-nav'
4392 if (this.parent() && this.parent().sidebar) {
4395 cls: 'dashboard-menu sidebar-menu'
4401 if (this.form === true) {
4404 cls: 'navbar-form form-inline'
4407 if (this.align === 'right') {
4408 cfg.cls += ' navbar-right ml-md-auto';
4410 cfg.cls += ' navbar-left';
4414 if (this.align === 'right') {
4415 cfg.cls += ' navbar-right ml-md-auto';
4417 cfg.cls += ' mr-auto';
4421 cfg.cls += ' navbar-inverse';
4429 * sets the active Navigation item
4430 * @param {Roo.bootstrap.NavItem} the new current navitem
4432 setActiveItem : function(item)
4435 Roo.each(this.navItems, function(v){
4440 v.setActive(false, true);
4447 item.setActive(true, true);
4448 this.fireEvent('changed', this, item, prev);
4453 * gets the active Navigation item
4454 * @return {Roo.bootstrap.NavItem} the current navitem
4456 getActive : function()
4460 Roo.each(this.navItems, function(v){
4471 indexOfNav : function()
4475 Roo.each(this.navItems, function(v,i){
4486 * adds a Navigation item
4487 * @param {Roo.bootstrap.NavItem} the navitem to add
4489 addItem : function(cfg)
4491 if (this.form && Roo.bootstrap.version == 4) {
4494 var cn = new Roo.bootstrap.NavItem(cfg);
4496 cn.parentId = this.id;
4497 cn.onRender(this.el, null);
4501 * register a Navigation item
4502 * @param {Roo.bootstrap.NavItem} the navitem to add
4504 register : function(item)
4506 this.navItems.push( item);
4507 item.navId = this.navId;
4512 * clear all the Navigation item
4515 clearAll : function()
4518 this.el.dom.innerHTML = '';
4521 getNavItem: function(tabId)
4524 Roo.each(this.navItems, function(e) {
4525 if (e.tabId == tabId) {
4535 setActiveNext : function()
4537 var i = this.indexOfNav(this.getActive());
4538 if (i > this.navItems.length) {
4541 this.setActiveItem(this.navItems[i+1]);
4543 setActivePrev : function()
4545 var i = this.indexOfNav(this.getActive());
4549 this.setActiveItem(this.navItems[i-1]);
4551 clearWasActive : function(except) {
4552 Roo.each(this.navItems, function(e) {
4553 if (e.tabId != except.tabId && e.was_active) {
4554 e.was_active = false;
4561 getWasActive : function ()
4564 Roo.each(this.navItems, function(e) {
4579 Roo.apply(Roo.bootstrap.NavGroup, {
4583 * register a Navigation Group
4584 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4586 register : function(navgrp)
4588 this.groups[navgrp.navId] = navgrp;
4592 * fetch a Navigation Group based on the navigation ID
4593 * @param {string} the navgroup to add
4594 * @returns {Roo.bootstrap.NavGroup} the navgroup
4596 get: function(navId) {
4597 if (typeof(this.groups[navId]) == 'undefined') {
4599 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4601 return this.groups[navId] ;
4616 * @class Roo.bootstrap.NavItem
4617 * @extends Roo.bootstrap.Component
4618 * Bootstrap Navbar.NavItem class
4619 * @cfg {String} href link to
4620 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4622 * @cfg {String} html content of button
4623 * @cfg {String} badge text inside badge
4624 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4625 * @cfg {String} glyphicon DEPRICATED - use fa
4626 * @cfg {String} icon DEPRICATED - use fa
4627 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4628 * @cfg {Boolean} active Is item active
4629 * @cfg {Boolean} disabled Is item disabled
4631 * @cfg {Boolean} preventDefault (true | false) default false
4632 * @cfg {String} tabId the tab that this item activates.
4633 * @cfg {String} tagtype (a|span) render as a href or span?
4634 * @cfg {Boolean} animateRef (true|false) link to element default false
4637 * Create a new Navbar Item
4638 * @param {Object} config The config object
4640 Roo.bootstrap.NavItem = function(config){
4641 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4646 * The raw click event for the entire grid.
4647 * @param {Roo.EventObject} e
4652 * Fires when the active item active state changes
4653 * @param {Roo.bootstrap.NavItem} this
4654 * @param {boolean} state the new state
4660 * Fires when scroll to element
4661 * @param {Roo.bootstrap.NavItem} this
4662 * @param {Object} options
4663 * @param {Roo.EventObject} e
4671 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4680 preventDefault : false,
4688 button_outline : false,
4692 getAutoCreate : function(){
4700 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4702 if (this.disabled) {
4703 cfg.cls += ' disabled';
4707 if (this.button_weight.length) {
4708 cfg.tag = this.href ? 'a' : 'button';
4709 cfg.html = this.html || '';
4710 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4712 cfg.href = this.href;
4715 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4718 // menu .. should add dropdown-menu class - so no need for carat..
4720 if (this.badge !== '') {
4722 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4727 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4731 href : this.href || "#",
4732 html: this.html || ''
4735 if (this.tagtype == 'a') {
4736 cfg.cn[0].cls = 'nav-link';
4739 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4742 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4744 if(this.glyphicon) {
4745 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4750 cfg.cn[0].html += " <span class='caret'></span>";
4754 if (this.badge !== '') {
4756 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4764 onRender : function(ct, position)
4766 // Roo.log("Call onRender: " + this.xtype);
4767 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4771 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4772 this.navLink = this.el.select('.nav-link',true).first();
4777 initEvents: function()
4779 if (typeof (this.menu) != 'undefined') {
4780 this.menu.parentType = this.xtype;
4781 this.menu.triggerEl = this.el;
4782 this.menu = this.addxtype(Roo.apply({}, this.menu));
4785 this.el.select('a',true).on('click', this.onClick, this);
4787 if(this.tagtype == 'span'){
4788 this.el.select('span',true).on('click', this.onClick, this);
4791 // at this point parent should be available..
4792 this.parent().register(this);
4795 onClick : function(e)
4797 if (e.getTarget('.dropdown-menu-item')) {
4798 // did you click on a menu itemm.... - then don't trigger onclick..
4803 this.preventDefault ||
4806 Roo.log("NavItem - prevent Default?");
4810 if (this.disabled) {
4814 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4815 if (tg && tg.transition) {
4816 Roo.log("waiting for the transitionend");
4822 //Roo.log("fire event clicked");
4823 if(this.fireEvent('click', this, e) === false){
4827 if(this.tagtype == 'span'){
4831 //Roo.log(this.href);
4832 var ael = this.el.select('a',true).first();
4835 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4836 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4837 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4838 return; // ignore... - it's a 'hash' to another page.
4840 Roo.log("NavItem - prevent Default?");
4842 this.scrollToElement(e);
4846 var p = this.parent();
4848 if (['tabs','pills'].indexOf(p.type)!==-1) {
4849 if (typeof(p.setActiveItem) !== 'undefined') {
4850 p.setActiveItem(this);
4854 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4855 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4856 // remove the collapsed menu expand...
4857 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4861 isActive: function () {
4864 setActive : function(state, fire, is_was_active)
4866 if (this.active && !state && this.navId) {
4867 this.was_active = true;
4868 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4870 nv.clearWasActive(this);
4874 this.active = state;
4877 this.el.removeClass('active');
4878 this.navLink ? this.navLink.removeClass('active') : false;
4879 } else if (!this.el.hasClass('active')) {
4881 this.el.addClass('active');
4882 if (Roo.bootstrap.version == 4 && this.navLink ) {
4883 this.navLink.addClass('active');
4888 this.fireEvent('changed', this, state);
4891 // show a panel if it's registered and related..
4893 if (!this.navId || !this.tabId || !state || is_was_active) {
4897 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4901 var pan = tg.getPanelByName(this.tabId);
4905 // if we can not flip to new panel - go back to old nav highlight..
4906 if (false == tg.showPanel(pan)) {
4907 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4909 var onav = nv.getWasActive();
4911 onav.setActive(true, false, true);
4920 // this should not be here...
4921 setDisabled : function(state)
4923 this.disabled = state;
4925 this.el.removeClass('disabled');
4926 } else if (!this.el.hasClass('disabled')) {
4927 this.el.addClass('disabled');
4933 * Fetch the element to display the tooltip on.
4934 * @return {Roo.Element} defaults to this.el
4936 tooltipEl : function()
4938 return this.el.select('' + this.tagtype + '', true).first();
4941 scrollToElement : function(e)
4943 var c = document.body;
4946 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4948 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4949 c = document.documentElement;
4952 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4958 var o = target.calcOffsetsTo(c);
4965 this.fireEvent('scrollto', this, options, e);
4967 Roo.get(c).scrollTo('top', options.value, true);
4980 * <span> icon </span>
4981 * <span> text </span>
4982 * <span>badge </span>
4986 * @class Roo.bootstrap.NavSidebarItem
4987 * @extends Roo.bootstrap.NavItem
4988 * Bootstrap Navbar.NavSidebarItem class
4989 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4990 * {Boolean} open is the menu open
4991 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4992 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4993 * {String} buttonSize (sm|md|lg)the extra classes for the button
4994 * {Boolean} showArrow show arrow next to the text (default true)
4996 * Create a new Navbar Button
4997 * @param {Object} config The config object
4999 Roo.bootstrap.NavSidebarItem = function(config){
5000 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5005 * The raw click event for the entire grid.
5006 * @param {Roo.EventObject} e
5011 * Fires when the active item active state changes
5012 * @param {Roo.bootstrap.NavSidebarItem} this
5013 * @param {boolean} state the new state
5021 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5023 badgeWeight : 'default',
5029 buttonWeight : 'default',
5035 getAutoCreate : function(){
5040 href : this.href || '#',
5046 if(this.buttonView){
5049 href : this.href || '#',
5050 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5063 cfg.cls += ' active';
5066 if (this.disabled) {
5067 cfg.cls += ' disabled';
5070 cfg.cls += ' open x-open';
5073 if (this.glyphicon || this.icon) {
5074 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5075 a.cn.push({ tag : 'i', cls : c }) ;
5078 if(!this.buttonView){
5081 html : this.html || ''
5088 if (this.badge !== '') {
5089 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5095 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5098 a.cls += ' dropdown-toggle treeview' ;
5104 initEvents : function()
5106 if (typeof (this.menu) != 'undefined') {
5107 this.menu.parentType = this.xtype;
5108 this.menu.triggerEl = this.el;
5109 this.menu = this.addxtype(Roo.apply({}, this.menu));
5112 this.el.on('click', this.onClick, this);
5114 if(this.badge !== ''){
5115 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5120 onClick : function(e)
5127 if(this.preventDefault){
5131 this.fireEvent('click', this);
5134 disable : function()
5136 this.setDisabled(true);
5141 this.setDisabled(false);
5144 setDisabled : function(state)
5146 if(this.disabled == state){
5150 this.disabled = state;
5153 this.el.addClass('disabled');
5157 this.el.removeClass('disabled');
5162 setActive : function(state)
5164 if(this.active == state){
5168 this.active = state;
5171 this.el.addClass('active');
5175 this.el.removeClass('active');
5180 isActive: function ()
5185 setBadge : function(str)
5191 this.badgeEl.dom.innerHTML = str;
5208 * @class Roo.bootstrap.Row
5209 * @extends Roo.bootstrap.Component
5210 * Bootstrap Row class (contains columns...)
5214 * @param {Object} config The config object
5217 Roo.bootstrap.Row = function(config){
5218 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5221 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5223 getAutoCreate : function(){
5242 * @class Roo.bootstrap.Element
5243 * @extends Roo.bootstrap.Component
5244 * Bootstrap Element class
5245 * @cfg {String} html contents of the element
5246 * @cfg {String} tag tag of the element
5247 * @cfg {String} cls class of the element
5248 * @cfg {Boolean} preventDefault (true|false) default false
5249 * @cfg {Boolean} clickable (true|false) default false
5252 * Create a new Element
5253 * @param {Object} config The config object
5256 Roo.bootstrap.Element = function(config){
5257 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5263 * When a element is chick
5264 * @param {Roo.bootstrap.Element} this
5265 * @param {Roo.EventObject} e
5271 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5276 preventDefault: false,
5279 getAutoCreate : function(){
5283 // cls: this.cls, double assign in parent class Component.js :: onRender
5290 initEvents: function()
5292 Roo.bootstrap.Element.superclass.initEvents.call(this);
5295 this.el.on('click', this.onClick, this);
5300 onClick : function(e)
5302 if(this.preventDefault){
5306 this.fireEvent('click', this, e);
5309 getValue : function()
5311 return this.el.dom.innerHTML;
5314 setValue : function(value)
5316 this.el.dom.innerHTML = value;
5331 * @class Roo.bootstrap.Pagination
5332 * @extends Roo.bootstrap.Component
5333 * Bootstrap Pagination class
5334 * @cfg {String} size xs | sm | md | lg
5335 * @cfg {Boolean} inverse false | true
5338 * Create a new Pagination
5339 * @param {Object} config The config object
5342 Roo.bootstrap.Pagination = function(config){
5343 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5346 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5352 getAutoCreate : function(){
5358 cfg.cls += ' inverse';
5364 cfg.cls += " " + this.cls;
5382 * @class Roo.bootstrap.PaginationItem
5383 * @extends Roo.bootstrap.Component
5384 * Bootstrap PaginationItem class
5385 * @cfg {String} html text
5386 * @cfg {String} href the link
5387 * @cfg {Boolean} preventDefault (true | false) default true
5388 * @cfg {Boolean} active (true | false) default false
5389 * @cfg {Boolean} disabled default false
5393 * Create a new PaginationItem
5394 * @param {Object} config The config object
5398 Roo.bootstrap.PaginationItem = function(config){
5399 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5404 * The raw click event for the entire grid.
5405 * @param {Roo.EventObject} e
5411 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5415 preventDefault: true,
5420 getAutoCreate : function(){
5426 href : this.href ? this.href : '#',
5427 html : this.html ? this.html : ''
5437 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5441 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5447 initEvents: function() {
5449 this.el.on('click', this.onClick, this);
5452 onClick : function(e)
5454 Roo.log('PaginationItem on click ');
5455 if(this.preventDefault){
5463 this.fireEvent('click', this, e);
5479 * @class Roo.bootstrap.Slider
5480 * @extends Roo.bootstrap.Component
5481 * Bootstrap Slider class
5484 * Create a new Slider
5485 * @param {Object} config The config object
5488 Roo.bootstrap.Slider = function(config){
5489 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5492 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5494 getAutoCreate : function(){
5498 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5502 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5514 * Ext JS Library 1.1.1
5515 * Copyright(c) 2006-2007, Ext JS, LLC.
5517 * Originally Released Under LGPL - original licence link has changed is not relivant.
5520 * <script type="text/javascript">
5525 * @class Roo.grid.ColumnModel
5526 * @extends Roo.util.Observable
5527 * This is the default implementation of a ColumnModel used by the Grid. It defines
5528 * the columns in the grid.
5531 var colModel = new Roo.grid.ColumnModel([
5532 {header: "Ticker", width: 60, sortable: true, locked: true},
5533 {header: "Company Name", width: 150, sortable: true},
5534 {header: "Market Cap.", width: 100, sortable: true},
5535 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5536 {header: "Employees", width: 100, sortable: true, resizable: false}
5541 * The config options listed for this class are options which may appear in each
5542 * individual column definition.
5543 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5545 * @param {Object} config An Array of column config objects. See this class's
5546 * config objects for details.
5548 Roo.grid.ColumnModel = function(config){
5550 * The config passed into the constructor
5552 this.config = config;
5555 // if no id, create one
5556 // if the column does not have a dataIndex mapping,
5557 // map it to the order it is in the config
5558 for(var i = 0, len = config.length; i < len; i++){
5560 if(typeof c.dataIndex == "undefined"){
5563 if(typeof c.renderer == "string"){
5564 c.renderer = Roo.util.Format[c.renderer];
5566 if(typeof c.id == "undefined"){
5569 if(c.editor && c.editor.xtype){
5570 c.editor = Roo.factory(c.editor, Roo.grid);
5572 if(c.editor && c.editor.isFormField){
5573 c.editor = new Roo.grid.GridEditor(c.editor);
5575 this.lookup[c.id] = c;
5579 * The width of columns which have no width specified (defaults to 100)
5582 this.defaultWidth = 100;
5585 * Default sortable of columns which have no sortable specified (defaults to false)
5588 this.defaultSortable = false;
5592 * @event widthchange
5593 * Fires when the width of a column changes.
5594 * @param {ColumnModel} this
5595 * @param {Number} columnIndex The column index
5596 * @param {Number} newWidth The new width
5598 "widthchange": true,
5600 * @event headerchange
5601 * Fires when the text of a header changes.
5602 * @param {ColumnModel} this
5603 * @param {Number} columnIndex The column index
5604 * @param {Number} newText The new header text
5606 "headerchange": true,
5608 * @event hiddenchange
5609 * Fires when a column is hidden or "unhidden".
5610 * @param {ColumnModel} this
5611 * @param {Number} columnIndex The column index
5612 * @param {Boolean} hidden true if hidden, false otherwise
5614 "hiddenchange": true,
5616 * @event columnmoved
5617 * Fires when a column is moved.
5618 * @param {ColumnModel} this
5619 * @param {Number} oldIndex
5620 * @param {Number} newIndex
5622 "columnmoved" : true,
5624 * @event columlockchange
5625 * Fires when a column's locked state is changed
5626 * @param {ColumnModel} this
5627 * @param {Number} colIndex
5628 * @param {Boolean} locked true if locked
5630 "columnlockchange" : true
5632 Roo.grid.ColumnModel.superclass.constructor.call(this);
5634 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5636 * @cfg {String} header The header text to display in the Grid view.
5639 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5640 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5641 * specified, the column's index is used as an index into the Record's data Array.
5644 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5645 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5648 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5649 * Defaults to the value of the {@link #defaultSortable} property.
5650 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5653 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5656 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5659 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5662 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5665 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5666 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5667 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5668 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5671 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5674 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5677 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5680 * @cfg {String} cursor (Optional)
5683 * @cfg {String} tooltip (Optional)
5686 * @cfg {Number} xs (Optional)
5689 * @cfg {Number} sm (Optional)
5692 * @cfg {Number} md (Optional)
5695 * @cfg {Number} lg (Optional)
5698 * Returns the id of the column at the specified index.
5699 * @param {Number} index The column index
5700 * @return {String} the id
5702 getColumnId : function(index){
5703 return this.config[index].id;
5707 * Returns the column for a specified id.
5708 * @param {String} id The column id
5709 * @return {Object} the column
5711 getColumnById : function(id){
5712 return this.lookup[id];
5717 * Returns the column for a specified dataIndex.
5718 * @param {String} dataIndex The column dataIndex
5719 * @return {Object|Boolean} the column or false if not found
5721 getColumnByDataIndex: function(dataIndex){
5722 var index = this.findColumnIndex(dataIndex);
5723 return index > -1 ? this.config[index] : false;
5727 * Returns the index for a specified column id.
5728 * @param {String} id The column id
5729 * @return {Number} the index, or -1 if not found
5731 getIndexById : function(id){
5732 for(var i = 0, len = this.config.length; i < len; i++){
5733 if(this.config[i].id == id){
5741 * Returns the index for a specified column dataIndex.
5742 * @param {String} dataIndex The column dataIndex
5743 * @return {Number} the index, or -1 if not found
5746 findColumnIndex : function(dataIndex){
5747 for(var i = 0, len = this.config.length; i < len; i++){
5748 if(this.config[i].dataIndex == dataIndex){
5756 moveColumn : function(oldIndex, newIndex){
5757 var c = this.config[oldIndex];
5758 this.config.splice(oldIndex, 1);
5759 this.config.splice(newIndex, 0, c);
5760 this.dataMap = null;
5761 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5764 isLocked : function(colIndex){
5765 return this.config[colIndex].locked === true;
5768 setLocked : function(colIndex, value, suppressEvent){
5769 if(this.isLocked(colIndex) == value){
5772 this.config[colIndex].locked = value;
5774 this.fireEvent("columnlockchange", this, colIndex, value);
5778 getTotalLockedWidth : function(){
5780 for(var i = 0; i < this.config.length; i++){
5781 if(this.isLocked(i) && !this.isHidden(i)){
5782 this.totalWidth += this.getColumnWidth(i);
5788 getLockedCount : function(){
5789 for(var i = 0, len = this.config.length; i < len; i++){
5790 if(!this.isLocked(i)){
5795 return this.config.length;
5799 * Returns the number of columns.
5802 getColumnCount : function(visibleOnly){
5803 if(visibleOnly === true){
5805 for(var i = 0, len = this.config.length; i < len; i++){
5806 if(!this.isHidden(i)){
5812 return this.config.length;
5816 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5817 * @param {Function} fn
5818 * @param {Object} scope (optional)
5819 * @return {Array} result
5821 getColumnsBy : function(fn, scope){
5823 for(var i = 0, len = this.config.length; i < len; i++){
5824 var c = this.config[i];
5825 if(fn.call(scope||this, c, i) === true){
5833 * Returns true if the specified column is sortable.
5834 * @param {Number} col The column index
5837 isSortable : function(col){
5838 if(typeof this.config[col].sortable == "undefined"){
5839 return this.defaultSortable;
5841 return this.config[col].sortable;
5845 * Returns the rendering (formatting) function defined for the column.
5846 * @param {Number} col The column index.
5847 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5849 getRenderer : function(col){
5850 if(!this.config[col].renderer){
5851 return Roo.grid.ColumnModel.defaultRenderer;
5853 return this.config[col].renderer;
5857 * Sets the rendering (formatting) function for a column.
5858 * @param {Number} col The column index
5859 * @param {Function} fn The function to use to process the cell's raw data
5860 * to return HTML markup for the grid view. The render function is called with
5861 * the following parameters:<ul>
5862 * <li>Data value.</li>
5863 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5864 * <li>css A CSS style string to apply to the table cell.</li>
5865 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5866 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5867 * <li>Row index</li>
5868 * <li>Column index</li>
5869 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5871 setRenderer : function(col, fn){
5872 this.config[col].renderer = fn;
5876 * Returns the width for the specified column.
5877 * @param {Number} col The column index
5880 getColumnWidth : function(col){
5881 return this.config[col].width * 1 || this.defaultWidth;
5885 * Sets the width for a column.
5886 * @param {Number} col The column index
5887 * @param {Number} width The new width
5889 setColumnWidth : function(col, width, suppressEvent){
5890 this.config[col].width = width;
5891 this.totalWidth = null;
5893 this.fireEvent("widthchange", this, col, width);
5898 * Returns the total width of all columns.
5899 * @param {Boolean} includeHidden True to include hidden column widths
5902 getTotalWidth : function(includeHidden){
5903 if(!this.totalWidth){
5904 this.totalWidth = 0;
5905 for(var i = 0, len = this.config.length; i < len; i++){
5906 if(includeHidden || !this.isHidden(i)){
5907 this.totalWidth += this.getColumnWidth(i);
5911 return this.totalWidth;
5915 * Returns the header for the specified column.
5916 * @param {Number} col The column index
5919 getColumnHeader : function(col){
5920 return this.config[col].header;
5924 * Sets the header for a column.
5925 * @param {Number} col The column index
5926 * @param {String} header The new header
5928 setColumnHeader : function(col, header){
5929 this.config[col].header = header;
5930 this.fireEvent("headerchange", this, col, header);
5934 * Returns the tooltip for the specified column.
5935 * @param {Number} col The column index
5938 getColumnTooltip : function(col){
5939 return this.config[col].tooltip;
5942 * Sets the tooltip for a column.
5943 * @param {Number} col The column index
5944 * @param {String} tooltip The new tooltip
5946 setColumnTooltip : function(col, tooltip){
5947 this.config[col].tooltip = tooltip;
5951 * Returns the dataIndex for the specified column.
5952 * @param {Number} col The column index
5955 getDataIndex : function(col){
5956 return this.config[col].dataIndex;
5960 * Sets the dataIndex for a column.
5961 * @param {Number} col The column index
5962 * @param {Number} dataIndex The new dataIndex
5964 setDataIndex : function(col, dataIndex){
5965 this.config[col].dataIndex = dataIndex;
5971 * Returns true if the cell is editable.
5972 * @param {Number} colIndex The column index
5973 * @param {Number} rowIndex The row index - this is nto actually used..?
5976 isCellEditable : function(colIndex, rowIndex){
5977 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5981 * Returns the editor defined for the cell/column.
5982 * return false or null to disable editing.
5983 * @param {Number} colIndex The column index
5984 * @param {Number} rowIndex The row index
5987 getCellEditor : function(colIndex, rowIndex){
5988 return this.config[colIndex].editor;
5992 * Sets if a column is editable.
5993 * @param {Number} col The column index
5994 * @param {Boolean} editable True if the column is editable
5996 setEditable : function(col, editable){
5997 this.config[col].editable = editable;
6002 * Returns true if the column is hidden.
6003 * @param {Number} colIndex The column index
6006 isHidden : function(colIndex){
6007 return this.config[colIndex].hidden;
6012 * Returns true if the column width cannot be changed
6014 isFixed : function(colIndex){
6015 return this.config[colIndex].fixed;
6019 * Returns true if the column can be resized
6022 isResizable : function(colIndex){
6023 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6026 * Sets if a column is hidden.
6027 * @param {Number} colIndex The column index
6028 * @param {Boolean} hidden True if the column is hidden
6030 setHidden : function(colIndex, hidden){
6031 this.config[colIndex].hidden = hidden;
6032 this.totalWidth = null;
6033 this.fireEvent("hiddenchange", this, colIndex, hidden);
6037 * Sets the editor for a column.
6038 * @param {Number} col The column index
6039 * @param {Object} editor The editor object
6041 setEditor : function(col, editor){
6042 this.config[col].editor = editor;
6046 Roo.grid.ColumnModel.defaultRenderer = function(value)
6048 if(typeof value == "object") {
6051 if(typeof value == "string" && value.length < 1){
6055 return String.format("{0}", value);
6058 // Alias for backwards compatibility
6059 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6062 * Ext JS Library 1.1.1
6063 * Copyright(c) 2006-2007, Ext JS, LLC.
6065 * Originally Released Under LGPL - original licence link has changed is not relivant.
6068 * <script type="text/javascript">
6072 * @class Roo.LoadMask
6073 * A simple utility class for generically masking elements while loading data. If the element being masked has
6074 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6075 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6076 * element's UpdateManager load indicator and will be destroyed after the initial load.
6078 * Create a new LoadMask
6079 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6080 * @param {Object} config The config object
6082 Roo.LoadMask = function(el, config){
6083 this.el = Roo.get(el);
6084 Roo.apply(this, config);
6086 this.store.on('beforeload', this.onBeforeLoad, this);
6087 this.store.on('load', this.onLoad, this);
6088 this.store.on('loadexception', this.onLoadException, this);
6089 this.removeMask = false;
6091 var um = this.el.getUpdateManager();
6092 um.showLoadIndicator = false; // disable the default indicator
6093 um.on('beforeupdate', this.onBeforeLoad, this);
6094 um.on('update', this.onLoad, this);
6095 um.on('failure', this.onLoad, this);
6096 this.removeMask = true;
6100 Roo.LoadMask.prototype = {
6102 * @cfg {Boolean} removeMask
6103 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6104 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6108 * The text to display in a centered loading message box (defaults to 'Loading...')
6112 * @cfg {String} msgCls
6113 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6115 msgCls : 'x-mask-loading',
6118 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6124 * Disables the mask to prevent it from being displayed
6126 disable : function(){
6127 this.disabled = true;
6131 * Enables the mask so that it can be displayed
6133 enable : function(){
6134 this.disabled = false;
6137 onLoadException : function()
6141 if (typeof(arguments[3]) != 'undefined') {
6142 Roo.MessageBox.alert("Error loading",arguments[3]);
6146 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6147 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6154 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6159 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6163 onBeforeLoad : function(){
6165 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6170 destroy : function(){
6172 this.store.un('beforeload', this.onBeforeLoad, this);
6173 this.store.un('load', this.onLoad, this);
6174 this.store.un('loadexception', this.onLoadException, this);
6176 var um = this.el.getUpdateManager();
6177 um.un('beforeupdate', this.onBeforeLoad, this);
6178 um.un('update', this.onLoad, this);
6179 um.un('failure', this.onLoad, this);
6190 * @class Roo.bootstrap.Table
6191 * @extends Roo.bootstrap.Component
6192 * Bootstrap Table class
6193 * @cfg {String} cls table class
6194 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6195 * @cfg {String} bgcolor Specifies the background color for a table
6196 * @cfg {Number} border Specifies whether the table cells should have borders or not
6197 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6198 * @cfg {Number} cellspacing Specifies the space between cells
6199 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6200 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6201 * @cfg {String} sortable Specifies that the table should be sortable
6202 * @cfg {String} summary Specifies a summary of the content of a table
6203 * @cfg {Number} width Specifies the width of a table
6204 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6206 * @cfg {boolean} striped Should the rows be alternative striped
6207 * @cfg {boolean} bordered Add borders to the table
6208 * @cfg {boolean} hover Add hover highlighting
6209 * @cfg {boolean} condensed Format condensed
6210 * @cfg {boolean} responsive Format condensed
6211 * @cfg {Boolean} loadMask (true|false) default false
6212 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6213 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6214 * @cfg {Boolean} rowSelection (true|false) default false
6215 * @cfg {Boolean} cellSelection (true|false) default false
6216 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6217 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6218 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6219 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6223 * Create a new Table
6224 * @param {Object} config The config object
6227 Roo.bootstrap.Table = function(config){
6228 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6233 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6234 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6235 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6236 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6238 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6240 this.sm.grid = this;
6241 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6242 this.sm = this.selModel;
6243 this.sm.xmodule = this.xmodule || false;
6246 if (this.cm && typeof(this.cm.config) == 'undefined') {
6247 this.colModel = new Roo.grid.ColumnModel(this.cm);
6248 this.cm = this.colModel;
6249 this.cm.xmodule = this.xmodule || false;
6252 this.store= Roo.factory(this.store, Roo.data);
6253 this.ds = this.store;
6254 this.ds.xmodule = this.xmodule || false;
6257 if (this.footer && this.store) {
6258 this.footer.dataSource = this.ds;
6259 this.footer = Roo.factory(this.footer);
6266 * Fires when a cell is clicked
6267 * @param {Roo.bootstrap.Table} this
6268 * @param {Roo.Element} el
6269 * @param {Number} rowIndex
6270 * @param {Number} columnIndex
6271 * @param {Roo.EventObject} e
6275 * @event celldblclick
6276 * Fires when a cell is double clicked
6277 * @param {Roo.bootstrap.Table} this
6278 * @param {Roo.Element} el
6279 * @param {Number} rowIndex
6280 * @param {Number} columnIndex
6281 * @param {Roo.EventObject} e
6283 "celldblclick" : true,
6286 * Fires when a row is clicked
6287 * @param {Roo.bootstrap.Table} this
6288 * @param {Roo.Element} el
6289 * @param {Number} rowIndex
6290 * @param {Roo.EventObject} e
6294 * @event rowdblclick
6295 * Fires when a row is double clicked
6296 * @param {Roo.bootstrap.Table} this
6297 * @param {Roo.Element} el
6298 * @param {Number} rowIndex
6299 * @param {Roo.EventObject} e
6301 "rowdblclick" : true,
6304 * Fires when a mouseover occur
6305 * @param {Roo.bootstrap.Table} this
6306 * @param {Roo.Element} el
6307 * @param {Number} rowIndex
6308 * @param {Number} columnIndex
6309 * @param {Roo.EventObject} e
6314 * Fires when a mouseout occur
6315 * @param {Roo.bootstrap.Table} this
6316 * @param {Roo.Element} el
6317 * @param {Number} rowIndex
6318 * @param {Number} columnIndex
6319 * @param {Roo.EventObject} e
6324 * Fires when a row is rendered, so you can change add a style to it.
6325 * @param {Roo.bootstrap.Table} this
6326 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6330 * @event rowsrendered
6331 * Fires when all the rows have been rendered
6332 * @param {Roo.bootstrap.Table} this
6334 'rowsrendered' : true,
6336 * @event contextmenu
6337 * The raw contextmenu event for the entire grid.
6338 * @param {Roo.EventObject} e
6340 "contextmenu" : true,
6342 * @event rowcontextmenu
6343 * Fires when a row is right clicked
6344 * @param {Roo.bootstrap.Table} this
6345 * @param {Number} rowIndex
6346 * @param {Roo.EventObject} e
6348 "rowcontextmenu" : true,
6350 * @event cellcontextmenu
6351 * Fires when a cell is right clicked
6352 * @param {Roo.bootstrap.Table} this
6353 * @param {Number} rowIndex
6354 * @param {Number} cellIndex
6355 * @param {Roo.EventObject} e
6357 "cellcontextmenu" : true,
6359 * @event headercontextmenu
6360 * Fires when a header is right clicked
6361 * @param {Roo.bootstrap.Table} this
6362 * @param {Number} columnIndex
6363 * @param {Roo.EventObject} e
6365 "headercontextmenu" : true
6369 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6395 rowSelection : false,
6396 cellSelection : false,
6399 // Roo.Element - the tbody
6401 // Roo.Element - thead element
6404 container: false, // used by gridpanel...
6410 auto_hide_footer : false,
6412 getAutoCreate : function()
6414 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6421 if (this.scrollBody) {
6422 cfg.cls += ' table-body-fixed';
6425 cfg.cls += ' table-striped';
6429 cfg.cls += ' table-hover';
6431 if (this.bordered) {
6432 cfg.cls += ' table-bordered';
6434 if (this.condensed) {
6435 cfg.cls += ' table-condensed';
6437 if (this.responsive) {
6438 cfg.cls += ' table-responsive';
6442 cfg.cls+= ' ' +this.cls;
6445 // this lot should be simplifed...
6458 ].forEach(function(k) {
6466 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6469 if(this.store || this.cm){
6470 if(this.headerShow){
6471 cfg.cn.push(this.renderHeader());
6474 cfg.cn.push(this.renderBody());
6476 if(this.footerShow){
6477 cfg.cn.push(this.renderFooter());
6479 // where does this come from?
6480 //cfg.cls+= ' TableGrid';
6483 return { cn : [ cfg ] };
6486 initEvents : function()
6488 if(!this.store || !this.cm){
6491 if (this.selModel) {
6492 this.selModel.initEvents();
6496 //Roo.log('initEvents with ds!!!!');
6498 this.mainBody = this.el.select('tbody', true).first();
6499 this.mainHead = this.el.select('thead', true).first();
6500 this.mainFoot = this.el.select('tfoot', true).first();
6506 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6507 e.on('click', _this.sort, _this);
6510 this.mainBody.on("click", this.onClick, this);
6511 this.mainBody.on("dblclick", this.onDblClick, this);
6513 // why is this done????? = it breaks dialogs??
6514 //this.parent().el.setStyle('position', 'relative');
6518 this.footer.parentId = this.id;
6519 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6522 this.el.select('tfoot tr td').first().addClass('hide');
6527 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6530 this.store.on('load', this.onLoad, this);
6531 this.store.on('beforeload', this.onBeforeLoad, this);
6532 this.store.on('update', this.onUpdate, this);
6533 this.store.on('add', this.onAdd, this);
6534 this.store.on("clear", this.clear, this);
6536 this.el.on("contextmenu", this.onContextMenu, this);
6538 this.mainBody.on('scroll', this.onBodyScroll, this);
6540 this.cm.on("headerchange", this.onHeaderChange, this);
6542 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6546 onContextMenu : function(e, t)
6548 this.processEvent("contextmenu", e);
6551 processEvent : function(name, e)
6553 if (name != 'touchstart' ) {
6554 this.fireEvent(name, e);
6557 var t = e.getTarget();
6559 var cell = Roo.get(t);
6565 if(cell.findParent('tfoot', false, true)){
6569 if(cell.findParent('thead', false, true)){
6571 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6572 cell = Roo.get(t).findParent('th', false, true);
6574 Roo.log("failed to find th in thead?");
6575 Roo.log(e.getTarget());
6580 var cellIndex = cell.dom.cellIndex;
6582 var ename = name == 'touchstart' ? 'click' : name;
6583 this.fireEvent("header" + ename, this, cellIndex, e);
6588 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6589 cell = Roo.get(t).findParent('td', false, true);
6591 Roo.log("failed to find th in tbody?");
6592 Roo.log(e.getTarget());
6597 var row = cell.findParent('tr', false, true);
6598 var cellIndex = cell.dom.cellIndex;
6599 var rowIndex = row.dom.rowIndex - 1;
6603 this.fireEvent("row" + name, this, rowIndex, e);
6607 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6613 onMouseover : function(e, el)
6615 var cell = Roo.get(el);
6621 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6622 cell = cell.findParent('td', false, true);
6625 var row = cell.findParent('tr', false, true);
6626 var cellIndex = cell.dom.cellIndex;
6627 var rowIndex = row.dom.rowIndex - 1; // start from 0
6629 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6633 onMouseout : function(e, el)
6635 var cell = Roo.get(el);
6641 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6642 cell = cell.findParent('td', false, true);
6645 var row = cell.findParent('tr', false, true);
6646 var cellIndex = cell.dom.cellIndex;
6647 var rowIndex = row.dom.rowIndex - 1; // start from 0
6649 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6653 onClick : function(e, el)
6655 var cell = Roo.get(el);
6657 if(!cell || (!this.cellSelection && !this.rowSelection)){
6661 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6662 cell = cell.findParent('td', false, true);
6665 if(!cell || typeof(cell) == 'undefined'){
6669 var row = cell.findParent('tr', false, true);
6671 if(!row || typeof(row) == 'undefined'){
6675 var cellIndex = cell.dom.cellIndex;
6676 var rowIndex = this.getRowIndex(row);
6678 // why??? - should these not be based on SelectionModel?
6679 if(this.cellSelection){
6680 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6683 if(this.rowSelection){
6684 this.fireEvent('rowclick', this, row, rowIndex, e);
6690 onDblClick : function(e,el)
6692 var cell = Roo.get(el);
6694 if(!cell || (!this.cellSelection && !this.rowSelection)){
6698 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6699 cell = cell.findParent('td', false, true);
6702 if(!cell || typeof(cell) == 'undefined'){
6706 var row = cell.findParent('tr', false, true);
6708 if(!row || typeof(row) == 'undefined'){
6712 var cellIndex = cell.dom.cellIndex;
6713 var rowIndex = this.getRowIndex(row);
6715 if(this.cellSelection){
6716 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6719 if(this.rowSelection){
6720 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6724 sort : function(e,el)
6726 var col = Roo.get(el);
6728 if(!col.hasClass('sortable')){
6732 var sort = col.attr('sort');
6735 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6739 this.store.sortInfo = {field : sort, direction : dir};
6742 Roo.log("calling footer first");
6743 this.footer.onClick('first');
6746 this.store.load({ params : { start : 0 } });
6750 renderHeader : function()
6758 this.totalWidth = 0;
6760 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6762 var config = cm.config[i];
6766 cls : 'x-hcol-' + i,
6768 html: cm.getColumnHeader(i)
6773 if(typeof(config.sortable) != 'undefined' && config.sortable){
6775 c.html = '<i class="glyphicon"></i>' + c.html;
6778 if(typeof(config.lgHeader) != 'undefined'){
6779 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6782 if(typeof(config.mdHeader) != 'undefined'){
6783 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6786 if(typeof(config.smHeader) != 'undefined'){
6787 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6790 if(typeof(config.xsHeader) != 'undefined'){
6791 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6798 if(typeof(config.tooltip) != 'undefined'){
6799 c.tooltip = config.tooltip;
6802 if(typeof(config.colspan) != 'undefined'){
6803 c.colspan = config.colspan;
6806 if(typeof(config.hidden) != 'undefined' && config.hidden){
6807 c.style += ' display:none;';
6810 if(typeof(config.dataIndex) != 'undefined'){
6811 c.sort = config.dataIndex;
6816 if(typeof(config.align) != 'undefined' && config.align.length){
6817 c.style += ' text-align:' + config.align + ';';
6820 if(typeof(config.width) != 'undefined'){
6821 c.style += ' width:' + config.width + 'px;';
6822 this.totalWidth += config.width;
6824 this.totalWidth += 100; // assume minimum of 100 per column?
6827 if(typeof(config.cls) != 'undefined'){
6828 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6831 ['xs','sm','md','lg'].map(function(size){
6833 if(typeof(config[size]) == 'undefined'){
6837 if (!config[size]) { // 0 = hidden
6838 c.cls += ' hidden-' + size;
6842 c.cls += ' col-' + size + '-' + config[size];
6852 renderBody : function()
6862 colspan : this.cm.getColumnCount()
6872 renderFooter : function()
6882 colspan : this.cm.getColumnCount()
6896 // Roo.log('ds onload');
6901 var ds = this.store;
6903 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6904 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6905 if (_this.store.sortInfo) {
6907 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6908 e.select('i', true).addClass(['glyphicon-arrow-up']);
6911 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6912 e.select('i', true).addClass(['glyphicon-arrow-down']);
6917 var tbody = this.mainBody;
6919 if(ds.getCount() > 0){
6920 ds.data.each(function(d,rowIndex){
6921 var row = this.renderRow(cm, ds, rowIndex);
6923 tbody.createChild(row);
6927 if(row.cellObjects.length){
6928 Roo.each(row.cellObjects, function(r){
6929 _this.renderCellObject(r);
6936 var tfoot = this.el.select('tfoot', true).first();
6938 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6940 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6942 var total = this.ds.getTotalCount();
6944 if(this.footer.pageSize < total){
6945 this.mainFoot.show();
6949 Roo.each(this.el.select('tbody td', true).elements, function(e){
6950 e.on('mouseover', _this.onMouseover, _this);
6953 Roo.each(this.el.select('tbody td', true).elements, function(e){
6954 e.on('mouseout', _this.onMouseout, _this);
6956 this.fireEvent('rowsrendered', this);
6962 onUpdate : function(ds,record)
6964 this.refreshRow(record);
6968 onRemove : function(ds, record, index, isUpdate){
6969 if(isUpdate !== true){
6970 this.fireEvent("beforerowremoved", this, index, record);
6972 var bt = this.mainBody.dom;
6974 var rows = this.el.select('tbody > tr', true).elements;
6976 if(typeof(rows[index]) != 'undefined'){
6977 bt.removeChild(rows[index].dom);
6980 // if(bt.rows[index]){
6981 // bt.removeChild(bt.rows[index]);
6984 if(isUpdate !== true){
6985 //this.stripeRows(index);
6986 //this.syncRowHeights(index, index);
6988 this.fireEvent("rowremoved", this, index, record);
6992 onAdd : function(ds, records, rowIndex)
6994 //Roo.log('on Add called');
6995 // - note this does not handle multiple adding very well..
6996 var bt = this.mainBody.dom;
6997 for (var i =0 ; i < records.length;i++) {
6998 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6999 //Roo.log(records[i]);
7000 //Roo.log(this.store.getAt(rowIndex+i));
7001 this.insertRow(this.store, rowIndex + i, false);
7008 refreshRow : function(record){
7009 var ds = this.store, index;
7010 if(typeof record == 'number'){
7012 record = ds.getAt(index);
7014 index = ds.indexOf(record);
7016 this.insertRow(ds, index, true);
7018 this.onRemove(ds, record, index+1, true);
7020 //this.syncRowHeights(index, index);
7022 this.fireEvent("rowupdated", this, index, record);
7025 insertRow : function(dm, rowIndex, isUpdate){
7028 this.fireEvent("beforerowsinserted", this, rowIndex);
7030 //var s = this.getScrollState();
7031 var row = this.renderRow(this.cm, this.store, rowIndex);
7032 // insert before rowIndex..
7033 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7037 if(row.cellObjects.length){
7038 Roo.each(row.cellObjects, function(r){
7039 _this.renderCellObject(r);
7044 this.fireEvent("rowsinserted", this, rowIndex);
7045 //this.syncRowHeights(firstRow, lastRow);
7046 //this.stripeRows(firstRow);
7053 getRowDom : function(rowIndex)
7055 var rows = this.el.select('tbody > tr', true).elements;
7057 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7060 // returns the object tree for a tr..
7063 renderRow : function(cm, ds, rowIndex)
7065 var d = ds.getAt(rowIndex);
7069 cls : 'x-row-' + rowIndex,
7073 var cellObjects = [];
7075 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7076 var config = cm.config[i];
7078 var renderer = cm.getRenderer(i);
7082 if(typeof(renderer) !== 'undefined'){
7083 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7085 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7086 // and are rendered into the cells after the row is rendered - using the id for the element.
7088 if(typeof(value) === 'object'){
7098 rowIndex : rowIndex,
7103 this.fireEvent('rowclass', this, rowcfg);
7107 cls : rowcfg.rowClass + ' x-col-' + i,
7109 html: (typeof(value) === 'object') ? '' : value
7116 if(typeof(config.colspan) != 'undefined'){
7117 td.colspan = config.colspan;
7120 if(typeof(config.hidden) != 'undefined' && config.hidden){
7121 td.style += ' display:none;';
7124 if(typeof(config.align) != 'undefined' && config.align.length){
7125 td.style += ' text-align:' + config.align + ';';
7127 if(typeof(config.valign) != 'undefined' && config.valign.length){
7128 td.style += ' vertical-align:' + config.valign + ';';
7131 if(typeof(config.width) != 'undefined'){
7132 td.style += ' width:' + config.width + 'px;';
7135 if(typeof(config.cursor) != 'undefined'){
7136 td.style += ' cursor:' + config.cursor + ';';
7139 if(typeof(config.cls) != 'undefined'){
7140 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7143 ['xs','sm','md','lg'].map(function(size){
7145 if(typeof(config[size]) == 'undefined'){
7149 if (!config[size]) { // 0 = hidden
7150 td.cls += ' hidden-' + size;
7154 td.cls += ' col-' + size + '-' + config[size];
7162 row.cellObjects = cellObjects;
7170 onBeforeLoad : function()
7179 this.el.select('tbody', true).first().dom.innerHTML = '';
7182 * Show or hide a row.
7183 * @param {Number} rowIndex to show or hide
7184 * @param {Boolean} state hide
7186 setRowVisibility : function(rowIndex, state)
7188 var bt = this.mainBody.dom;
7190 var rows = this.el.select('tbody > tr', true).elements;
7192 if(typeof(rows[rowIndex]) == 'undefined'){
7195 rows[rowIndex].dom.style.display = state ? '' : 'none';
7199 getSelectionModel : function(){
7201 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7203 return this.selModel;
7206 * Render the Roo.bootstrap object from renderder
7208 renderCellObject : function(r)
7212 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7214 var t = r.cfg.render(r.container);
7217 Roo.each(r.cfg.cn, function(c){
7219 container: t.getChildContainer(),
7222 _this.renderCellObject(child);
7227 getRowIndex : function(row)
7231 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7242 * Returns the grid's underlying element = used by panel.Grid
7243 * @return {Element} The element
7245 getGridEl : function(){
7249 * Forces a resize - used by panel.Grid
7250 * @return {Element} The element
7252 autoSize : function()
7254 //var ctr = Roo.get(this.container.dom.parentElement);
7255 var ctr = Roo.get(this.el.dom);
7257 var thd = this.getGridEl().select('thead',true).first();
7258 var tbd = this.getGridEl().select('tbody', true).first();
7259 var tfd = this.getGridEl().select('tfoot', true).first();
7261 var cw = ctr.getWidth();
7265 tbd.setSize(ctr.getWidth(),
7266 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7268 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7271 cw = Math.max(cw, this.totalWidth);
7272 this.getGridEl().select('tr',true).setWidth(cw);
7273 // resize 'expandable coloumn?
7275 return; // we doe not have a view in this design..
7278 onBodyScroll: function()
7280 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7282 this.mainHead.setStyle({
7283 'position' : 'relative',
7284 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7290 var scrollHeight = this.mainBody.dom.scrollHeight;
7292 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7294 var height = this.mainBody.getHeight();
7296 if(scrollHeight - height == scrollTop) {
7298 var total = this.ds.getTotalCount();
7300 if(this.footer.cursor + this.footer.pageSize < total){
7302 this.footer.ds.load({
7304 start : this.footer.cursor + this.footer.pageSize,
7305 limit : this.footer.pageSize
7315 onHeaderChange : function()
7317 var header = this.renderHeader();
7318 var table = this.el.select('table', true).first();
7320 this.mainHead.remove();
7321 this.mainHead = table.createChild(header, this.mainBody, false);
7324 onHiddenChange : function(colModel, colIndex, hidden)
7326 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7327 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7329 this.CSS.updateRule(thSelector, "display", "");
7330 this.CSS.updateRule(tdSelector, "display", "");
7333 this.CSS.updateRule(thSelector, "display", "none");
7334 this.CSS.updateRule(tdSelector, "display", "none");
7337 this.onHeaderChange();
7341 setColumnWidth: function(col_index, width)
7343 // width = "md-2 xs-2..."
7344 if(!this.colModel.config[col_index]) {
7348 var w = width.split(" ");
7350 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7352 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7355 for(var j = 0; j < w.length; j++) {
7361 var size_cls = w[j].split("-");
7363 if(!Number.isInteger(size_cls[1] * 1)) {
7367 if(!this.colModel.config[col_index][size_cls[0]]) {
7371 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7375 h_row[0].classList.replace(
7376 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7377 "col-"+size_cls[0]+"-"+size_cls[1]
7380 for(var i = 0; i < rows.length; i++) {
7382 var size_cls = w[j].split("-");
7384 if(!Number.isInteger(size_cls[1] * 1)) {
7388 if(!this.colModel.config[col_index][size_cls[0]]) {
7392 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7396 rows[i].classList.replace(
7397 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7398 "col-"+size_cls[0]+"-"+size_cls[1]
7402 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7417 * @class Roo.bootstrap.TableCell
7418 * @extends Roo.bootstrap.Component
7419 * Bootstrap TableCell class
7420 * @cfg {String} html cell contain text
7421 * @cfg {String} cls cell class
7422 * @cfg {String} tag cell tag (td|th) default td
7423 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7424 * @cfg {String} align Aligns the content in a cell
7425 * @cfg {String} axis Categorizes cells
7426 * @cfg {String} bgcolor Specifies the background color of a cell
7427 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7428 * @cfg {Number} colspan Specifies the number of columns a cell should span
7429 * @cfg {String} headers Specifies one or more header cells a cell is related to
7430 * @cfg {Number} height Sets the height of a cell
7431 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7432 * @cfg {Number} rowspan Sets the number of rows a cell should span
7433 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7434 * @cfg {String} valign Vertical aligns the content in a cell
7435 * @cfg {Number} width Specifies the width of a cell
7438 * Create a new TableCell
7439 * @param {Object} config The config object
7442 Roo.bootstrap.TableCell = function(config){
7443 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7446 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7466 getAutoCreate : function(){
7467 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7487 cfg.align=this.align
7493 cfg.bgcolor=this.bgcolor
7496 cfg.charoff=this.charoff
7499 cfg.colspan=this.colspan
7502 cfg.headers=this.headers
7505 cfg.height=this.height
7508 cfg.nowrap=this.nowrap
7511 cfg.rowspan=this.rowspan
7514 cfg.scope=this.scope
7517 cfg.valign=this.valign
7520 cfg.width=this.width
7539 * @class Roo.bootstrap.TableRow
7540 * @extends Roo.bootstrap.Component
7541 * Bootstrap TableRow class
7542 * @cfg {String} cls row class
7543 * @cfg {String} align Aligns the content in a table row
7544 * @cfg {String} bgcolor Specifies a background color for a table row
7545 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7546 * @cfg {String} valign Vertical aligns the content in a table row
7549 * Create a new TableRow
7550 * @param {Object} config The config object
7553 Roo.bootstrap.TableRow = function(config){
7554 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7557 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7565 getAutoCreate : function(){
7566 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7576 cfg.align = this.align;
7579 cfg.bgcolor = this.bgcolor;
7582 cfg.charoff = this.charoff;
7585 cfg.valign = this.valign;
7603 * @class Roo.bootstrap.TableBody
7604 * @extends Roo.bootstrap.Component
7605 * Bootstrap TableBody class
7606 * @cfg {String} cls element class
7607 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7608 * @cfg {String} align Aligns the content inside the element
7609 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7610 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7613 * Create a new TableBody
7614 * @param {Object} config The config object
7617 Roo.bootstrap.TableBody = function(config){
7618 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7621 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7629 getAutoCreate : function(){
7630 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7644 cfg.align = this.align;
7647 cfg.charoff = this.charoff;
7650 cfg.valign = this.valign;
7657 // initEvents : function()
7664 // this.store = Roo.factory(this.store, Roo.data);
7665 // this.store.on('load', this.onLoad, this);
7667 // this.store.load();
7671 // onLoad: function ()
7673 // this.fireEvent('load', this);
7683 * Ext JS Library 1.1.1
7684 * Copyright(c) 2006-2007, Ext JS, LLC.
7686 * Originally Released Under LGPL - original licence link has changed is not relivant.
7689 * <script type="text/javascript">
7692 // as we use this in bootstrap.
7693 Roo.namespace('Roo.form');
7695 * @class Roo.form.Action
7696 * Internal Class used to handle form actions
7698 * @param {Roo.form.BasicForm} el The form element or its id
7699 * @param {Object} config Configuration options
7704 // define the action interface
7705 Roo.form.Action = function(form, options){
7707 this.options = options || {};
7710 * Client Validation Failed
7713 Roo.form.Action.CLIENT_INVALID = 'client';
7715 * Server Validation Failed
7718 Roo.form.Action.SERVER_INVALID = 'server';
7720 * Connect to Server Failed
7723 Roo.form.Action.CONNECT_FAILURE = 'connect';
7725 * Reading Data from Server Failed
7728 Roo.form.Action.LOAD_FAILURE = 'load';
7730 Roo.form.Action.prototype = {
7732 failureType : undefined,
7733 response : undefined,
7737 run : function(options){
7742 success : function(response){
7747 handleResponse : function(response){
7751 // default connection failure
7752 failure : function(response){
7754 this.response = response;
7755 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7756 this.form.afterAction(this, false);
7759 processResponse : function(response){
7760 this.response = response;
7761 if(!response.responseText){
7764 this.result = this.handleResponse(response);
7768 // utility functions used internally
7769 getUrl : function(appendParams){
7770 var url = this.options.url || this.form.url || this.form.el.dom.action;
7772 var p = this.getParams();
7774 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7780 getMethod : function(){
7781 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7784 getParams : function(){
7785 var bp = this.form.baseParams;
7786 var p = this.options.params;
7788 if(typeof p == "object"){
7789 p = Roo.urlEncode(Roo.applyIf(p, bp));
7790 }else if(typeof p == 'string' && bp){
7791 p += '&' + Roo.urlEncode(bp);
7794 p = Roo.urlEncode(bp);
7799 createCallback : function(){
7801 success: this.success,
7802 failure: this.failure,
7804 timeout: (this.form.timeout*1000),
7805 upload: this.form.fileUpload ? this.success : undefined
7810 Roo.form.Action.Submit = function(form, options){
7811 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7814 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7817 haveProgress : false,
7818 uploadComplete : false,
7820 // uploadProgress indicator.
7821 uploadProgress : function()
7823 if (!this.form.progressUrl) {
7827 if (!this.haveProgress) {
7828 Roo.MessageBox.progress("Uploading", "Uploading");
7830 if (this.uploadComplete) {
7831 Roo.MessageBox.hide();
7835 this.haveProgress = true;
7837 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7839 var c = new Roo.data.Connection();
7841 url : this.form.progressUrl,
7846 success : function(req){
7847 //console.log(data);
7851 rdata = Roo.decode(req.responseText)
7853 Roo.log("Invalid data from server..");
7857 if (!rdata || !rdata.success) {
7859 Roo.MessageBox.alert(Roo.encode(rdata));
7862 var data = rdata.data;
7864 if (this.uploadComplete) {
7865 Roo.MessageBox.hide();
7870 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7871 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7874 this.uploadProgress.defer(2000,this);
7877 failure: function(data) {
7878 Roo.log('progress url failed ');
7889 // run get Values on the form, so it syncs any secondary forms.
7890 this.form.getValues();
7892 var o = this.options;
7893 var method = this.getMethod();
7894 var isPost = method == 'POST';
7895 if(o.clientValidation === false || this.form.isValid()){
7897 if (this.form.progressUrl) {
7898 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7899 (new Date() * 1) + '' + Math.random());
7904 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7905 form:this.form.el.dom,
7906 url:this.getUrl(!isPost),
7908 params:isPost ? this.getParams() : null,
7909 isUpload: this.form.fileUpload
7912 this.uploadProgress();
7914 }else if (o.clientValidation !== false){ // client validation failed
7915 this.failureType = Roo.form.Action.CLIENT_INVALID;
7916 this.form.afterAction(this, false);
7920 success : function(response)
7922 this.uploadComplete= true;
7923 if (this.haveProgress) {
7924 Roo.MessageBox.hide();
7928 var result = this.processResponse(response);
7929 if(result === true || result.success){
7930 this.form.afterAction(this, true);
7934 this.form.markInvalid(result.errors);
7935 this.failureType = Roo.form.Action.SERVER_INVALID;
7937 this.form.afterAction(this, false);
7939 failure : function(response)
7941 this.uploadComplete= true;
7942 if (this.haveProgress) {
7943 Roo.MessageBox.hide();
7946 this.response = response;
7947 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7948 this.form.afterAction(this, false);
7951 handleResponse : function(response){
7952 if(this.form.errorReader){
7953 var rs = this.form.errorReader.read(response);
7956 for(var i = 0, len = rs.records.length; i < len; i++) {
7957 var r = rs.records[i];
7961 if(errors.length < 1){
7965 success : rs.success,
7971 ret = Roo.decode(response.responseText);
7975 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7985 Roo.form.Action.Load = function(form, options){
7986 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7987 this.reader = this.form.reader;
7990 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7995 Roo.Ajax.request(Roo.apply(
7996 this.createCallback(), {
7997 method:this.getMethod(),
7998 url:this.getUrl(false),
7999 params:this.getParams()
8003 success : function(response){
8005 var result = this.processResponse(response);
8006 if(result === true || !result.success || !result.data){
8007 this.failureType = Roo.form.Action.LOAD_FAILURE;
8008 this.form.afterAction(this, false);
8011 this.form.clearInvalid();
8012 this.form.setValues(result.data);
8013 this.form.afterAction(this, true);
8016 handleResponse : function(response){
8017 if(this.form.reader){
8018 var rs = this.form.reader.read(response);
8019 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8021 success : rs.success,
8025 return Roo.decode(response.responseText);
8029 Roo.form.Action.ACTION_TYPES = {
8030 'load' : Roo.form.Action.Load,
8031 'submit' : Roo.form.Action.Submit
8040 * @class Roo.bootstrap.Form
8041 * @extends Roo.bootstrap.Component
8042 * Bootstrap Form class
8043 * @cfg {String} method GET | POST (default POST)
8044 * @cfg {String} labelAlign top | left (default top)
8045 * @cfg {String} align left | right - for navbars
8046 * @cfg {Boolean} loadMask load mask when submit (default true)
8051 * @param {Object} config The config object
8055 Roo.bootstrap.Form = function(config){
8057 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8059 Roo.bootstrap.Form.popover.apply();
8063 * @event clientvalidation
8064 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8065 * @param {Form} this
8066 * @param {Boolean} valid true if the form has passed client-side validation
8068 clientvalidation: true,
8070 * @event beforeaction
8071 * Fires before any action is performed. Return false to cancel the action.
8072 * @param {Form} this
8073 * @param {Action} action The action to be performed
8077 * @event actionfailed
8078 * Fires when an action fails.
8079 * @param {Form} this
8080 * @param {Action} action The action that failed
8082 actionfailed : true,
8084 * @event actioncomplete
8085 * Fires when an action is completed.
8086 * @param {Form} this
8087 * @param {Action} action The action that completed
8089 actioncomplete : true
8093 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8096 * @cfg {String} method
8097 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8102 * The URL to use for form actions if one isn't supplied in the action options.
8105 * @cfg {Boolean} fileUpload
8106 * Set to true if this form is a file upload.
8110 * @cfg {Object} baseParams
8111 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8115 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8119 * @cfg {Sting} align (left|right) for navbar forms
8124 activeAction : null,
8127 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8128 * element by passing it or its id or mask the form itself by passing in true.
8131 waitMsgTarget : false,
8136 * @cfg {Boolean} errorMask (true|false) default false
8141 * @cfg {Number} maskOffset Default 100
8146 * @cfg {Boolean} maskBody
8150 getAutoCreate : function(){
8154 method : this.method || 'POST',
8155 id : this.id || Roo.id(),
8158 if (this.parent().xtype.match(/^Nav/)) {
8159 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8163 if (this.labelAlign == 'left' ) {
8164 cfg.cls += ' form-horizontal';
8170 initEvents : function()
8172 this.el.on('submit', this.onSubmit, this);
8173 // this was added as random key presses on the form where triggering form submit.
8174 this.el.on('keypress', function(e) {
8175 if (e.getCharCode() != 13) {
8178 // we might need to allow it for textareas.. and some other items.
8179 // check e.getTarget().
8181 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8185 Roo.log("keypress blocked");
8193 onSubmit : function(e){
8198 * Returns true if client-side validation on the form is successful.
8201 isValid : function(){
8202 var items = this.getItems();
8206 items.each(function(f){
8212 Roo.log('invalid field: ' + f.name);
8216 if(!target && f.el.isVisible(true)){
8222 if(this.errorMask && !valid){
8223 Roo.bootstrap.Form.popover.mask(this, target);
8230 * Returns true if any fields in this form have changed since their original load.
8233 isDirty : function(){
8235 var items = this.getItems();
8236 items.each(function(f){
8246 * Performs a predefined action (submit or load) or custom actions you define on this form.
8247 * @param {String} actionName The name of the action type
8248 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8249 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8250 * accept other config options):
8252 Property Type Description
8253 ---------------- --------------- ----------------------------------------------------------------------------------
8254 url String The url for the action (defaults to the form's url)
8255 method String The form method to use (defaults to the form's method, or POST if not defined)
8256 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8257 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8258 validate the form on the client (defaults to false)
8260 * @return {BasicForm} this
8262 doAction : function(action, options){
8263 if(typeof action == 'string'){
8264 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8266 if(this.fireEvent('beforeaction', this, action) !== false){
8267 this.beforeAction(action);
8268 action.run.defer(100, action);
8274 beforeAction : function(action){
8275 var o = action.options;
8280 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8282 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8285 // not really supported yet.. ??
8287 //if(this.waitMsgTarget === true){
8288 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8289 //}else if(this.waitMsgTarget){
8290 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8291 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8293 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8299 afterAction : function(action, success){
8300 this.activeAction = null;
8301 var o = action.options;
8306 Roo.get(document.body).unmask();
8312 //if(this.waitMsgTarget === true){
8313 // this.el.unmask();
8314 //}else if(this.waitMsgTarget){
8315 // this.waitMsgTarget.unmask();
8317 // Roo.MessageBox.updateProgress(1);
8318 // Roo.MessageBox.hide();
8325 Roo.callback(o.success, o.scope, [this, action]);
8326 this.fireEvent('actioncomplete', this, action);
8330 // failure condition..
8331 // we have a scenario where updates need confirming.
8332 // eg. if a locking scenario exists..
8333 // we look for { errors : { needs_confirm : true }} in the response.
8335 (typeof(action.result) != 'undefined') &&
8336 (typeof(action.result.errors) != 'undefined') &&
8337 (typeof(action.result.errors.needs_confirm) != 'undefined')
8340 Roo.log("not supported yet");
8343 Roo.MessageBox.confirm(
8344 "Change requires confirmation",
8345 action.result.errorMsg,
8350 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8360 Roo.callback(o.failure, o.scope, [this, action]);
8361 // show an error message if no failed handler is set..
8362 if (!this.hasListener('actionfailed')) {
8363 Roo.log("need to add dialog support");
8365 Roo.MessageBox.alert("Error",
8366 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8367 action.result.errorMsg :
8368 "Saving Failed, please check your entries or try again"
8373 this.fireEvent('actionfailed', this, action);
8378 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8379 * @param {String} id The value to search for
8382 findField : function(id){
8383 var items = this.getItems();
8384 var field = items.get(id);
8386 items.each(function(f){
8387 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8394 return field || null;
8397 * Mark fields in this form invalid in bulk.
8398 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8399 * @return {BasicForm} this
8401 markInvalid : function(errors){
8402 if(errors instanceof Array){
8403 for(var i = 0, len = errors.length; i < len; i++){
8404 var fieldError = errors[i];
8405 var f = this.findField(fieldError.id);
8407 f.markInvalid(fieldError.msg);
8413 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8414 field.markInvalid(errors[id]);
8418 //Roo.each(this.childForms || [], function (f) {
8419 // f.markInvalid(errors);
8426 * Set values for fields in this form in bulk.
8427 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8428 * @return {BasicForm} this
8430 setValues : function(values){
8431 if(values instanceof Array){ // array of objects
8432 for(var i = 0, len = values.length; i < len; i++){
8434 var f = this.findField(v.id);
8436 f.setValue(v.value);
8437 if(this.trackResetOnLoad){
8438 f.originalValue = f.getValue();
8442 }else{ // object hash
8445 if(typeof values[id] != 'function' && (field = this.findField(id))){
8447 if (field.setFromData &&
8449 field.displayField &&
8450 // combos' with local stores can
8451 // be queried via setValue()
8452 // to set their value..
8453 (field.store && !field.store.isLocal)
8457 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8458 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8459 field.setFromData(sd);
8461 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8463 field.setFromData(values);
8466 field.setValue(values[id]);
8470 if(this.trackResetOnLoad){
8471 field.originalValue = field.getValue();
8477 //Roo.each(this.childForms || [], function (f) {
8478 // f.setValues(values);
8485 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8486 * they are returned as an array.
8487 * @param {Boolean} asString
8490 getValues : function(asString){
8491 //if (this.childForms) {
8492 // copy values from the child forms
8493 // Roo.each(this.childForms, function (f) {
8494 // this.setValues(f.getValues());
8500 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8501 if(asString === true){
8504 return Roo.urlDecode(fs);
8508 * Returns the fields in this form as an object with key/value pairs.
8509 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8512 getFieldValues : function(with_hidden)
8514 var items = this.getItems();
8516 items.each(function(f){
8522 var v = f.getValue();
8524 if (f.inputType =='radio') {
8525 if (typeof(ret[f.getName()]) == 'undefined') {
8526 ret[f.getName()] = ''; // empty..
8529 if (!f.el.dom.checked) {
8537 if(f.xtype == 'MoneyField'){
8538 ret[f.currencyName] = f.getCurrency();
8541 // not sure if this supported any more..
8542 if ((typeof(v) == 'object') && f.getRawValue) {
8543 v = f.getRawValue() ; // dates..
8545 // combo boxes where name != hiddenName...
8546 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8547 ret[f.name] = f.getRawValue();
8549 ret[f.getName()] = v;
8556 * Clears all invalid messages in this form.
8557 * @return {BasicForm} this
8559 clearInvalid : function(){
8560 var items = this.getItems();
8562 items.each(function(f){
8571 * @return {BasicForm} this
8574 var items = this.getItems();
8575 items.each(function(f){
8579 Roo.each(this.childForms || [], function (f) {
8587 getItems : function()
8589 var r=new Roo.util.MixedCollection(false, function(o){
8590 return o.id || (o.id = Roo.id());
8592 var iter = function(el) {
8599 Roo.each(el.items,function(e) {
8608 hideFields : function(items)
8610 Roo.each(items, function(i){
8612 var f = this.findField(i);
8623 showFields : function(items)
8625 Roo.each(items, function(i){
8627 var f = this.findField(i);
8640 Roo.apply(Roo.bootstrap.Form, {
8667 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8668 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8669 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8670 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8673 this.maskEl.top.enableDisplayMode("block");
8674 this.maskEl.left.enableDisplayMode("block");
8675 this.maskEl.bottom.enableDisplayMode("block");
8676 this.maskEl.right.enableDisplayMode("block");
8678 this.toolTip = new Roo.bootstrap.Tooltip({
8679 cls : 'roo-form-error-popover',
8681 'left' : ['r-l', [-2,0], 'right'],
8682 'right' : ['l-r', [2,0], 'left'],
8683 'bottom' : ['tl-bl', [0,2], 'top'],
8684 'top' : [ 'bl-tl', [0,-2], 'bottom']
8688 this.toolTip.render(Roo.get(document.body));
8690 this.toolTip.el.enableDisplayMode("block");
8692 Roo.get(document.body).on('click', function(){
8696 Roo.get(document.body).on('touchstart', function(){
8700 this.isApplied = true
8703 mask : function(form, target)
8707 this.target = target;
8709 if(!this.form.errorMask || !target.el){
8713 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8715 Roo.log(scrollable);
8717 var ot = this.target.el.calcOffsetsTo(scrollable);
8719 var scrollTo = ot[1] - this.form.maskOffset;
8721 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8723 scrollable.scrollTo('top', scrollTo);
8725 var box = this.target.el.getBox();
8727 var zIndex = Roo.bootstrap.Modal.zIndex++;
8730 this.maskEl.top.setStyle('position', 'absolute');
8731 this.maskEl.top.setStyle('z-index', zIndex);
8732 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8733 this.maskEl.top.setLeft(0);
8734 this.maskEl.top.setTop(0);
8735 this.maskEl.top.show();
8737 this.maskEl.left.setStyle('position', 'absolute');
8738 this.maskEl.left.setStyle('z-index', zIndex);
8739 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8740 this.maskEl.left.setLeft(0);
8741 this.maskEl.left.setTop(box.y - this.padding);
8742 this.maskEl.left.show();
8744 this.maskEl.bottom.setStyle('position', 'absolute');
8745 this.maskEl.bottom.setStyle('z-index', zIndex);
8746 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8747 this.maskEl.bottom.setLeft(0);
8748 this.maskEl.bottom.setTop(box.bottom + this.padding);
8749 this.maskEl.bottom.show();
8751 this.maskEl.right.setStyle('position', 'absolute');
8752 this.maskEl.right.setStyle('z-index', zIndex);
8753 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8754 this.maskEl.right.setLeft(box.right + this.padding);
8755 this.maskEl.right.setTop(box.y - this.padding);
8756 this.maskEl.right.show();
8758 this.toolTip.bindEl = this.target.el;
8760 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8762 var tip = this.target.blankText;
8764 if(this.target.getValue() !== '' ) {
8766 if (this.target.invalidText.length) {
8767 tip = this.target.invalidText;
8768 } else if (this.target.regexText.length){
8769 tip = this.target.regexText;
8773 this.toolTip.show(tip);
8775 this.intervalID = window.setInterval(function() {
8776 Roo.bootstrap.Form.popover.unmask();
8779 window.onwheel = function(){ return false;};
8781 (function(){ this.isMasked = true; }).defer(500, this);
8787 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8791 this.maskEl.top.setStyle('position', 'absolute');
8792 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8793 this.maskEl.top.hide();
8795 this.maskEl.left.setStyle('position', 'absolute');
8796 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8797 this.maskEl.left.hide();
8799 this.maskEl.bottom.setStyle('position', 'absolute');
8800 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8801 this.maskEl.bottom.hide();
8803 this.maskEl.right.setStyle('position', 'absolute');
8804 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8805 this.maskEl.right.hide();
8807 this.toolTip.hide();
8809 this.toolTip.el.hide();
8811 window.onwheel = function(){ return true;};
8813 if(this.intervalID){
8814 window.clearInterval(this.intervalID);
8815 this.intervalID = false;
8818 this.isMasked = false;
8828 * Ext JS Library 1.1.1
8829 * Copyright(c) 2006-2007, Ext JS, LLC.
8831 * Originally Released Under LGPL - original licence link has changed is not relivant.
8834 * <script type="text/javascript">
8837 * @class Roo.form.VTypes
8838 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8841 Roo.form.VTypes = function(){
8842 // closure these in so they are only created once.
8843 var alpha = /^[a-zA-Z_]+$/;
8844 var alphanum = /^[a-zA-Z0-9_]+$/;
8845 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8846 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8848 // All these messages and functions are configurable
8851 * The function used to validate email addresses
8852 * @param {String} value The email address
8854 'email' : function(v){
8855 return email.test(v);
8858 * The error text to display when the email validation function returns false
8861 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8863 * The keystroke filter mask to be applied on email input
8866 'emailMask' : /[a-z0-9_\.\-@]/i,
8869 * The function used to validate URLs
8870 * @param {String} value The URL
8872 'url' : function(v){
8876 * The error text to display when the url validation function returns false
8879 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8882 * The function used to validate alpha values
8883 * @param {String} value The value
8885 'alpha' : function(v){
8886 return alpha.test(v);
8889 * The error text to display when the alpha validation function returns false
8892 'alphaText' : 'This field should only contain letters and _',
8894 * The keystroke filter mask to be applied on alpha input
8897 'alphaMask' : /[a-z_]/i,
8900 * The function used to validate alphanumeric values
8901 * @param {String} value The value
8903 'alphanum' : function(v){
8904 return alphanum.test(v);
8907 * The error text to display when the alphanumeric validation function returns false
8910 'alphanumText' : 'This field should only contain letters, numbers and _',
8912 * The keystroke filter mask to be applied on alphanumeric input
8915 'alphanumMask' : /[a-z0-9_]/i
8925 * @class Roo.bootstrap.Input
8926 * @extends Roo.bootstrap.Component
8927 * Bootstrap Input class
8928 * @cfg {Boolean} disabled is it disabled
8929 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8930 * @cfg {String} name name of the input
8931 * @cfg {string} fieldLabel - the label associated
8932 * @cfg {string} placeholder - placeholder to put in text.
8933 * @cfg {string} before - input group add on before
8934 * @cfg {string} after - input group add on after
8935 * @cfg {string} size - (lg|sm) or leave empty..
8936 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8937 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8938 * @cfg {Number} md colspan out of 12 for computer-sized screens
8939 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8940 * @cfg {string} value default value of the input
8941 * @cfg {Number} labelWidth set the width of label
8942 * @cfg {Number} labellg set the width of label (1-12)
8943 * @cfg {Number} labelmd set the width of label (1-12)
8944 * @cfg {Number} labelsm set the width of label (1-12)
8945 * @cfg {Number} labelxs set the width of label (1-12)
8946 * @cfg {String} labelAlign (top|left)
8947 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8948 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8949 * @cfg {String} indicatorpos (left|right) default left
8950 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8951 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8953 * @cfg {String} align (left|center|right) Default left
8954 * @cfg {Boolean} forceFeedback (true|false) Default false
8957 * Create a new Input
8958 * @param {Object} config The config object
8961 Roo.bootstrap.Input = function(config){
8963 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8968 * Fires when this field receives input focus.
8969 * @param {Roo.form.Field} this
8974 * Fires when this field loses input focus.
8975 * @param {Roo.form.Field} this
8980 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8981 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8982 * @param {Roo.form.Field} this
8983 * @param {Roo.EventObject} e The event object
8988 * Fires just before the field blurs if the field value has changed.
8989 * @param {Roo.form.Field} this
8990 * @param {Mixed} newValue The new value
8991 * @param {Mixed} oldValue The original value
8996 * Fires after the field has been marked as invalid.
8997 * @param {Roo.form.Field} this
8998 * @param {String} msg The validation message
9003 * Fires after the field has been validated with no errors.
9004 * @param {Roo.form.Field} this
9009 * Fires after the key up
9010 * @param {Roo.form.Field} this
9011 * @param {Roo.EventObject} e The event Object
9017 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9019 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9020 automatic validation (defaults to "keyup").
9022 validationEvent : "keyup",
9024 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9026 validateOnBlur : true,
9028 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9030 validationDelay : 250,
9032 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9034 focusClass : "x-form-focus", // not needed???
9038 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9040 invalidClass : "has-warning",
9043 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9045 validClass : "has-success",
9048 * @cfg {Boolean} hasFeedback (true|false) default true
9053 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9055 invalidFeedbackClass : "glyphicon-warning-sign",
9058 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9060 validFeedbackClass : "glyphicon-ok",
9063 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9065 selectOnFocus : false,
9068 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9072 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9077 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9079 disableKeyFilter : false,
9082 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9086 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9090 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9092 blankText : "Please complete this mandatory field",
9095 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9099 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9101 maxLength : Number.MAX_VALUE,
9103 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9105 minLengthText : "The minimum length for this field is {0}",
9107 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9109 maxLengthText : "The maximum length for this field is {0}",
9113 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9114 * If available, this function will be called only after the basic validators all return true, and will be passed the
9115 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9119 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9120 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9121 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9125 * @cfg {String} regexText -- Depricated - use Invalid Text
9130 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9136 autocomplete: false,
9155 formatedValue : false,
9156 forceFeedback : false,
9158 indicatorpos : 'left',
9168 parentLabelAlign : function()
9171 while (parent.parent()) {
9172 parent = parent.parent();
9173 if (typeof(parent.labelAlign) !='undefined') {
9174 return parent.labelAlign;
9181 getAutoCreate : function()
9183 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9189 if(this.inputType != 'hidden'){
9190 cfg.cls = 'form-group' //input-group
9196 type : this.inputType,
9198 cls : 'form-control',
9199 placeholder : this.placeholder || '',
9200 autocomplete : this.autocomplete || 'new-password'
9203 if(this.capture.length){
9204 input.capture = this.capture;
9207 if(this.accept.length){
9208 input.accept = this.accept + "/*";
9212 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9215 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9216 input.maxLength = this.maxLength;
9219 if (this.disabled) {
9220 input.disabled=true;
9223 if (this.readOnly) {
9224 input.readonly=true;
9228 input.name = this.name;
9232 input.cls += ' input-' + this.size;
9236 ['xs','sm','md','lg'].map(function(size){
9237 if (settings[size]) {
9238 cfg.cls += ' col-' + size + '-' + settings[size];
9242 var inputblock = input;
9246 cls: 'glyphicon form-control-feedback'
9249 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9252 cls : 'has-feedback',
9260 if (this.before || this.after) {
9263 cls : 'input-group',
9267 if (this.before && typeof(this.before) == 'string') {
9269 inputblock.cn.push({
9271 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9275 if (this.before && typeof(this.before) == 'object') {
9276 this.before = Roo.factory(this.before);
9278 inputblock.cn.push({
9280 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9281 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9285 inputblock.cn.push(input);
9287 if (this.after && typeof(this.after) == 'string') {
9288 inputblock.cn.push({
9290 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9294 if (this.after && typeof(this.after) == 'object') {
9295 this.after = Roo.factory(this.after);
9297 inputblock.cn.push({
9299 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9300 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9304 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9305 inputblock.cls += ' has-feedback';
9306 inputblock.cn.push(feedback);
9311 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9312 tooltip : 'This field is required'
9314 if (Roo.bootstrap.version == 4) {
9317 style : 'display-none'
9320 if (align ==='left' && this.fieldLabel.length) {
9322 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9329 cls : 'control-label col-form-label',
9330 html : this.fieldLabel
9341 var labelCfg = cfg.cn[1];
9342 var contentCfg = cfg.cn[2];
9344 if(this.indicatorpos == 'right'){
9349 cls : 'control-label col-form-label',
9353 html : this.fieldLabel
9367 labelCfg = cfg.cn[0];
9368 contentCfg = cfg.cn[1];
9372 if(this.labelWidth > 12){
9373 labelCfg.style = "width: " + this.labelWidth + 'px';
9376 if(this.labelWidth < 13 && this.labelmd == 0){
9377 this.labelmd = this.labelWidth;
9380 if(this.labellg > 0){
9381 labelCfg.cls += ' col-lg-' + this.labellg;
9382 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9385 if(this.labelmd > 0){
9386 labelCfg.cls += ' col-md-' + this.labelmd;
9387 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9390 if(this.labelsm > 0){
9391 labelCfg.cls += ' col-sm-' + this.labelsm;
9392 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9395 if(this.labelxs > 0){
9396 labelCfg.cls += ' col-xs-' + this.labelxs;
9397 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9401 } else if ( this.fieldLabel.length) {
9406 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9407 tooltip : 'This field is required'
9411 //cls : 'input-group-addon',
9412 html : this.fieldLabel
9420 if(this.indicatorpos == 'right'){
9425 //cls : 'input-group-addon',
9426 html : this.fieldLabel
9431 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9432 tooltip : 'This field is required'
9452 if (this.parentType === 'Navbar' && this.parent().bar) {
9453 cfg.cls += ' navbar-form';
9456 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9457 // on BS4 we do this only if not form
9458 cfg.cls += ' navbar-form';
9466 * return the real input element.
9468 inputEl: function ()
9470 return this.el.select('input.form-control',true).first();
9473 tooltipEl : function()
9475 return this.inputEl();
9478 indicatorEl : function()
9480 if (Roo.bootstrap.version == 4) {
9481 return false; // not enabled in v4 yet.
9484 var indicator = this.el.select('i.roo-required-indicator',true).first();
9494 setDisabled : function(v)
9496 var i = this.inputEl().dom;
9498 i.removeAttribute('disabled');
9502 i.setAttribute('disabled','true');
9504 initEvents : function()
9507 this.inputEl().on("keydown" , this.fireKey, this);
9508 this.inputEl().on("focus", this.onFocus, this);
9509 this.inputEl().on("blur", this.onBlur, this);
9511 this.inputEl().relayEvent('keyup', this);
9513 this.indicator = this.indicatorEl();
9516 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9519 // reference to original value for reset
9520 this.originalValue = this.getValue();
9521 //Roo.form.TextField.superclass.initEvents.call(this);
9522 if(this.validationEvent == 'keyup'){
9523 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9524 this.inputEl().on('keyup', this.filterValidation, this);
9526 else if(this.validationEvent !== false){
9527 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9530 if(this.selectOnFocus){
9531 this.on("focus", this.preFocus, this);
9534 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9535 this.inputEl().on("keypress", this.filterKeys, this);
9537 this.inputEl().relayEvent('keypress', this);
9540 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9541 this.el.on("click", this.autoSize, this);
9544 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9545 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9548 if (typeof(this.before) == 'object') {
9549 this.before.render(this.el.select('.roo-input-before',true).first());
9551 if (typeof(this.after) == 'object') {
9552 this.after.render(this.el.select('.roo-input-after',true).first());
9555 this.inputEl().on('change', this.onChange, this);
9558 filterValidation : function(e){
9559 if(!e.isNavKeyPress()){
9560 this.validationTask.delay(this.validationDelay);
9564 * Validates the field value
9565 * @return {Boolean} True if the value is valid, else false
9567 validate : function(){
9568 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9569 if(this.disabled || this.validateValue(this.getRawValue())){
9580 * Validates a value according to the field's validation rules and marks the field as invalid
9581 * if the validation fails
9582 * @param {Mixed} value The value to validate
9583 * @return {Boolean} True if the value is valid, else false
9585 validateValue : function(value)
9587 if(this.getVisibilityEl().hasClass('hidden')){
9591 if(value.length < 1) { // if it's blank
9592 if(this.allowBlank){
9598 if(value.length < this.minLength){
9601 if(value.length > this.maxLength){
9605 var vt = Roo.form.VTypes;
9606 if(!vt[this.vtype](value, this)){
9610 if(typeof this.validator == "function"){
9611 var msg = this.validator(value);
9615 if (typeof(msg) == 'string') {
9616 this.invalidText = msg;
9620 if(this.regex && !this.regex.test(value)){
9628 fireKey : function(e){
9629 //Roo.log('field ' + e.getKey());
9630 if(e.isNavKeyPress()){
9631 this.fireEvent("specialkey", this, e);
9634 focus : function (selectText){
9636 this.inputEl().focus();
9637 if(selectText === true){
9638 this.inputEl().dom.select();
9644 onFocus : function(){
9645 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9646 // this.el.addClass(this.focusClass);
9649 this.hasFocus = true;
9650 this.startValue = this.getValue();
9651 this.fireEvent("focus", this);
9655 beforeBlur : Roo.emptyFn,
9659 onBlur : function(){
9661 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9662 //this.el.removeClass(this.focusClass);
9664 this.hasFocus = false;
9665 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9668 var v = this.getValue();
9669 if(String(v) !== String(this.startValue)){
9670 this.fireEvent('change', this, v, this.startValue);
9672 this.fireEvent("blur", this);
9675 onChange : function(e)
9677 var v = this.getValue();
9678 if(String(v) !== String(this.startValue)){
9679 this.fireEvent('change', this, v, this.startValue);
9685 * Resets the current field value to the originally loaded value and clears any validation messages
9688 this.setValue(this.originalValue);
9692 * Returns the name of the field
9693 * @return {Mixed} name The name field
9695 getName: function(){
9699 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9700 * @return {Mixed} value The field value
9702 getValue : function(){
9704 var v = this.inputEl().getValue();
9709 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9710 * @return {Mixed} value The field value
9712 getRawValue : function(){
9713 var v = this.inputEl().getValue();
9719 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9720 * @param {Mixed} value The value to set
9722 setRawValue : function(v){
9723 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9726 selectText : function(start, end){
9727 var v = this.getRawValue();
9729 start = start === undefined ? 0 : start;
9730 end = end === undefined ? v.length : end;
9731 var d = this.inputEl().dom;
9732 if(d.setSelectionRange){
9733 d.setSelectionRange(start, end);
9734 }else if(d.createTextRange){
9735 var range = d.createTextRange();
9736 range.moveStart("character", start);
9737 range.moveEnd("character", v.length-end);
9744 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9745 * @param {Mixed} value The value to set
9747 setValue : function(v){
9750 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9756 processValue : function(value){
9757 if(this.stripCharsRe){
9758 var newValue = value.replace(this.stripCharsRe, '');
9759 if(newValue !== value){
9760 this.setRawValue(newValue);
9767 preFocus : function(){
9769 if(this.selectOnFocus){
9770 this.inputEl().dom.select();
9773 filterKeys : function(e){
9775 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9778 var c = e.getCharCode(), cc = String.fromCharCode(c);
9779 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9782 if(!this.maskRe.test(cc)){
9787 * Clear any invalid styles/messages for this field
9789 clearInvalid : function(){
9791 if(!this.el || this.preventMark){ // not rendered
9796 this.el.removeClass([this.invalidClass, 'is-invalid']);
9798 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9800 var feedback = this.el.select('.form-control-feedback', true).first();
9803 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9809 this.indicator.removeClass('visible');
9810 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9813 this.fireEvent('valid', this);
9817 * Mark this field as valid
9819 markValid : function()
9821 if(!this.el || this.preventMark){ // not rendered...
9825 this.el.removeClass([this.invalidClass, this.validClass]);
9826 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9828 var feedback = this.el.select('.form-control-feedback', true).first();
9831 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9835 this.indicator.removeClass('visible');
9836 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9843 if(this.allowBlank && !this.getRawValue().length){
9846 if (Roo.bootstrap.version == 3) {
9847 this.el.addClass(this.validClass);
9849 this.inputEl().addClass('is-valid');
9852 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9854 var feedback = this.el.select('.form-control-feedback', true).first();
9857 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9858 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9863 this.fireEvent('valid', this);
9867 * Mark this field as invalid
9868 * @param {String} msg The validation message
9870 markInvalid : function(msg)
9872 if(!this.el || this.preventMark){ // not rendered
9876 this.el.removeClass([this.invalidClass, this.validClass]);
9877 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9879 var feedback = this.el.select('.form-control-feedback', true).first();
9882 this.el.select('.form-control-feedback', true).first().removeClass(
9883 [this.invalidFeedbackClass, this.validFeedbackClass]);
9890 if(this.allowBlank && !this.getRawValue().length){
9895 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9896 this.indicator.addClass('visible');
9898 if (Roo.bootstrap.version == 3) {
9899 this.el.addClass(this.invalidClass);
9901 this.inputEl().addClass('is-invalid');
9906 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9908 var feedback = this.el.select('.form-control-feedback', true).first();
9911 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9913 if(this.getValue().length || this.forceFeedback){
9914 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9921 this.fireEvent('invalid', this, msg);
9924 SafariOnKeyDown : function(event)
9926 // this is a workaround for a password hang bug on chrome/ webkit.
9927 if (this.inputEl().dom.type != 'password') {
9931 var isSelectAll = false;
9933 if(this.inputEl().dom.selectionEnd > 0){
9934 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9936 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9937 event.preventDefault();
9942 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9944 event.preventDefault();
9945 // this is very hacky as keydown always get's upper case.
9947 var cc = String.fromCharCode(event.getCharCode());
9948 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9952 adjustWidth : function(tag, w){
9953 tag = tag.toLowerCase();
9954 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9955 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9959 if(tag == 'textarea'){
9962 }else if(Roo.isOpera){
9966 if(tag == 'textarea'){
9974 setFieldLabel : function(v)
9980 if(this.indicatorEl()){
9981 var ar = this.el.select('label > span',true);
9983 if (ar.elements.length) {
9984 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9985 this.fieldLabel = v;
9989 var br = this.el.select('label',true);
9991 if(br.elements.length) {
9992 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9993 this.fieldLabel = v;
9997 Roo.log('Cannot Found any of label > span || label in input');
10001 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10002 this.fieldLabel = v;
10017 * @class Roo.bootstrap.TextArea
10018 * @extends Roo.bootstrap.Input
10019 * Bootstrap TextArea class
10020 * @cfg {Number} cols Specifies the visible width of a text area
10021 * @cfg {Number} rows Specifies the visible number of lines in a text area
10022 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10023 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10024 * @cfg {string} html text
10027 * Create a new TextArea
10028 * @param {Object} config The config object
10031 Roo.bootstrap.TextArea = function(config){
10032 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10036 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10046 getAutoCreate : function(){
10048 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10054 if(this.inputType != 'hidden'){
10055 cfg.cls = 'form-group' //input-group
10063 value : this.value || '',
10064 html: this.html || '',
10065 cls : 'form-control',
10066 placeholder : this.placeholder || ''
10070 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10071 input.maxLength = this.maxLength;
10075 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10079 input.cols = this.cols;
10082 if (this.readOnly) {
10083 input.readonly = true;
10087 input.name = this.name;
10091 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10095 ['xs','sm','md','lg'].map(function(size){
10096 if (settings[size]) {
10097 cfg.cls += ' col-' + size + '-' + settings[size];
10101 var inputblock = input;
10103 if(this.hasFeedback && !this.allowBlank){
10107 cls: 'glyphicon form-control-feedback'
10111 cls : 'has-feedback',
10120 if (this.before || this.after) {
10123 cls : 'input-group',
10127 inputblock.cn.push({
10129 cls : 'input-group-addon',
10134 inputblock.cn.push(input);
10136 if(this.hasFeedback && !this.allowBlank){
10137 inputblock.cls += ' has-feedback';
10138 inputblock.cn.push(feedback);
10142 inputblock.cn.push({
10144 cls : 'input-group-addon',
10151 if (align ==='left' && this.fieldLabel.length) {
10156 cls : 'control-label',
10157 html : this.fieldLabel
10168 if(this.labelWidth > 12){
10169 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10172 if(this.labelWidth < 13 && this.labelmd == 0){
10173 this.labelmd = this.labelWidth;
10176 if(this.labellg > 0){
10177 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10178 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10181 if(this.labelmd > 0){
10182 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10183 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10186 if(this.labelsm > 0){
10187 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10188 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10191 if(this.labelxs > 0){
10192 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10193 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10196 } else if ( this.fieldLabel.length) {
10201 //cls : 'input-group-addon',
10202 html : this.fieldLabel
10220 if (this.disabled) {
10221 input.disabled=true;
10228 * return the real textarea element.
10230 inputEl: function ()
10232 return this.el.select('textarea.form-control',true).first();
10236 * Clear any invalid styles/messages for this field
10238 clearInvalid : function()
10241 if(!this.el || this.preventMark){ // not rendered
10245 var label = this.el.select('label', true).first();
10246 var icon = this.el.select('i.fa-star', true).first();
10251 this.el.removeClass( this.validClass);
10252 this.inputEl().removeClass('is-invalid');
10254 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10256 var feedback = this.el.select('.form-control-feedback', true).first();
10259 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10264 this.fireEvent('valid', this);
10268 * Mark this field as valid
10270 markValid : function()
10272 if(!this.el || this.preventMark){ // not rendered
10276 this.el.removeClass([this.invalidClass, this.validClass]);
10277 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10279 var feedback = this.el.select('.form-control-feedback', true).first();
10282 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10285 if(this.disabled || this.allowBlank){
10289 var label = this.el.select('label', true).first();
10290 var icon = this.el.select('i.fa-star', true).first();
10295 if (Roo.bootstrap.version == 3) {
10296 this.el.addClass(this.validClass);
10298 this.inputEl().addClass('is-valid');
10302 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10304 var feedback = this.el.select('.form-control-feedback', true).first();
10307 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10308 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10313 this.fireEvent('valid', this);
10317 * Mark this field as invalid
10318 * @param {String} msg The validation message
10320 markInvalid : function(msg)
10322 if(!this.el || this.preventMark){ // not rendered
10326 this.el.removeClass([this.invalidClass, this.validClass]);
10327 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10329 var feedback = this.el.select('.form-control-feedback', true).first();
10332 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10335 if(this.disabled || this.allowBlank){
10339 var label = this.el.select('label', true).first();
10340 var icon = this.el.select('i.fa-star', true).first();
10342 if(!this.getValue().length && label && !icon){
10343 this.el.createChild({
10345 cls : 'text-danger fa fa-lg fa-star',
10346 tooltip : 'This field is required',
10347 style : 'margin-right:5px;'
10351 if (Roo.bootstrap.version == 3) {
10352 this.el.addClass(this.invalidClass);
10354 this.inputEl().addClass('is-invalid');
10357 // fixme ... this may be depricated need to test..
10358 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10360 var feedback = this.el.select('.form-control-feedback', true).first();
10363 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10365 if(this.getValue().length || this.forceFeedback){
10366 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10373 this.fireEvent('invalid', this, msg);
10381 * trigger field - base class for combo..
10386 * @class Roo.bootstrap.TriggerField
10387 * @extends Roo.bootstrap.Input
10388 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10389 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10390 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10391 * for which you can provide a custom implementation. For example:
10393 var trigger = new Roo.bootstrap.TriggerField();
10394 trigger.onTriggerClick = myTriggerFn;
10395 trigger.applyTo('my-field');
10398 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10399 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10400 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10401 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10402 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10405 * Create a new TriggerField.
10406 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10407 * to the base TextField)
10409 Roo.bootstrap.TriggerField = function(config){
10410 this.mimicing = false;
10411 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10414 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10416 * @cfg {String} triggerClass A CSS class to apply to the trigger
10419 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10424 * @cfg {Boolean} removable (true|false) special filter default false
10428 /** @cfg {Boolean} grow @hide */
10429 /** @cfg {Number} growMin @hide */
10430 /** @cfg {Number} growMax @hide */
10436 autoSize: Roo.emptyFn,
10440 deferHeight : true,
10443 actionMode : 'wrap',
10448 getAutoCreate : function(){
10450 var align = this.labelAlign || this.parentLabelAlign();
10455 cls: 'form-group' //input-group
10462 type : this.inputType,
10463 cls : 'form-control',
10464 autocomplete: 'new-password',
10465 placeholder : this.placeholder || ''
10469 input.name = this.name;
10472 input.cls += ' input-' + this.size;
10475 if (this.disabled) {
10476 input.disabled=true;
10479 var inputblock = input;
10481 if(this.hasFeedback && !this.allowBlank){
10485 cls: 'glyphicon form-control-feedback'
10488 if(this.removable && !this.editable && !this.tickable){
10490 cls : 'has-feedback',
10496 cls : 'roo-combo-removable-btn close'
10503 cls : 'has-feedback',
10512 if(this.removable && !this.editable && !this.tickable){
10514 cls : 'roo-removable',
10520 cls : 'roo-combo-removable-btn close'
10527 if (this.before || this.after) {
10530 cls : 'input-group',
10534 inputblock.cn.push({
10536 cls : 'input-group-addon input-group-prepend input-group-text',
10541 inputblock.cn.push(input);
10543 if(this.hasFeedback && !this.allowBlank){
10544 inputblock.cls += ' has-feedback';
10545 inputblock.cn.push(feedback);
10549 inputblock.cn.push({
10551 cls : 'input-group-addon input-group-append input-group-text',
10560 var ibwrap = inputblock;
10565 cls: 'roo-select2-choices',
10569 cls: 'roo-select2-search-field',
10581 cls: 'roo-select2-container input-group',
10586 cls: 'form-hidden-field'
10592 if(!this.multiple && this.showToggleBtn){
10598 if (this.caret != false) {
10601 cls: 'fa fa-' + this.caret
10608 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10613 cls: 'combobox-clear',
10627 combobox.cls += ' roo-select2-container-multi';
10631 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10632 tooltip : 'This field is required'
10634 if (Roo.bootstrap.version == 4) {
10637 style : 'display:none'
10642 if (align ==='left' && this.fieldLabel.length) {
10644 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10651 cls : 'control-label',
10652 html : this.fieldLabel
10664 var labelCfg = cfg.cn[1];
10665 var contentCfg = cfg.cn[2];
10667 if(this.indicatorpos == 'right'){
10672 cls : 'control-label',
10676 html : this.fieldLabel
10690 labelCfg = cfg.cn[0];
10691 contentCfg = cfg.cn[1];
10694 if(this.labelWidth > 12){
10695 labelCfg.style = "width: " + this.labelWidth + 'px';
10698 if(this.labelWidth < 13 && this.labelmd == 0){
10699 this.labelmd = this.labelWidth;
10702 if(this.labellg > 0){
10703 labelCfg.cls += ' col-lg-' + this.labellg;
10704 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10707 if(this.labelmd > 0){
10708 labelCfg.cls += ' col-md-' + this.labelmd;
10709 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10712 if(this.labelsm > 0){
10713 labelCfg.cls += ' col-sm-' + this.labelsm;
10714 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10717 if(this.labelxs > 0){
10718 labelCfg.cls += ' col-xs-' + this.labelxs;
10719 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10722 } else if ( this.fieldLabel.length) {
10723 // Roo.log(" label");
10728 //cls : 'input-group-addon',
10729 html : this.fieldLabel
10737 if(this.indicatorpos == 'right'){
10745 html : this.fieldLabel
10759 // Roo.log(" no label && no align");
10766 ['xs','sm','md','lg'].map(function(size){
10767 if (settings[size]) {
10768 cfg.cls += ' col-' + size + '-' + settings[size];
10779 onResize : function(w, h){
10780 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10781 // if(typeof w == 'number'){
10782 // var x = w - this.trigger.getWidth();
10783 // this.inputEl().setWidth(this.adjustWidth('input', x));
10784 // this.trigger.setStyle('left', x+'px');
10789 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10792 getResizeEl : function(){
10793 return this.inputEl();
10797 getPositionEl : function(){
10798 return this.inputEl();
10802 alignErrorIcon : function(){
10803 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10807 initEvents : function(){
10811 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10812 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10813 if(!this.multiple && this.showToggleBtn){
10814 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10815 if(this.hideTrigger){
10816 this.trigger.setDisplayed(false);
10818 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10822 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10825 if(this.removable && !this.editable && !this.tickable){
10826 var close = this.closeTriggerEl();
10829 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10830 close.on('click', this.removeBtnClick, this, close);
10834 //this.trigger.addClassOnOver('x-form-trigger-over');
10835 //this.trigger.addClassOnClick('x-form-trigger-click');
10838 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10842 closeTriggerEl : function()
10844 var close = this.el.select('.roo-combo-removable-btn', true).first();
10845 return close ? close : false;
10848 removeBtnClick : function(e, h, el)
10850 e.preventDefault();
10852 if(this.fireEvent("remove", this) !== false){
10854 this.fireEvent("afterremove", this)
10858 createList : function()
10860 this.list = Roo.get(document.body).createChild({
10861 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10862 cls: 'typeahead typeahead-long dropdown-menu',
10863 style: 'display:none'
10866 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10871 initTrigger : function(){
10876 onDestroy : function(){
10878 this.trigger.removeAllListeners();
10879 // this.trigger.remove();
10882 // this.wrap.remove();
10884 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10888 onFocus : function(){
10889 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10891 if(!this.mimicing){
10892 this.wrap.addClass('x-trigger-wrap-focus');
10893 this.mimicing = true;
10894 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10895 if(this.monitorTab){
10896 this.el.on("keydown", this.checkTab, this);
10903 checkTab : function(e){
10904 if(e.getKey() == e.TAB){
10905 this.triggerBlur();
10910 onBlur : function(){
10915 mimicBlur : function(e, t){
10917 if(!this.wrap.contains(t) && this.validateBlur()){
10918 this.triggerBlur();
10924 triggerBlur : function(){
10925 this.mimicing = false;
10926 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10927 if(this.monitorTab){
10928 this.el.un("keydown", this.checkTab, this);
10930 //this.wrap.removeClass('x-trigger-wrap-focus');
10931 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10935 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10936 validateBlur : function(e, t){
10941 onDisable : function(){
10942 this.inputEl().dom.disabled = true;
10943 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10945 // this.wrap.addClass('x-item-disabled');
10950 onEnable : function(){
10951 this.inputEl().dom.disabled = false;
10952 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10954 // this.el.removeClass('x-item-disabled');
10959 onShow : function(){
10960 var ae = this.getActionEl();
10963 ae.dom.style.display = '';
10964 ae.dom.style.visibility = 'visible';
10970 onHide : function(){
10971 var ae = this.getActionEl();
10972 ae.dom.style.display = 'none';
10976 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10977 * by an implementing function.
10979 * @param {EventObject} e
10981 onTriggerClick : Roo.emptyFn
10985 * Ext JS Library 1.1.1
10986 * Copyright(c) 2006-2007, Ext JS, LLC.
10988 * Originally Released Under LGPL - original licence link has changed is not relivant.
10991 * <script type="text/javascript">
10996 * @class Roo.data.SortTypes
10998 * Defines the default sorting (casting?) comparison functions used when sorting data.
11000 Roo.data.SortTypes = {
11002 * Default sort that does nothing
11003 * @param {Mixed} s The value being converted
11004 * @return {Mixed} The comparison value
11006 none : function(s){
11011 * The regular expression used to strip tags
11015 stripTagsRE : /<\/?[^>]+>/gi,
11018 * Strips all HTML tags to sort on text only
11019 * @param {Mixed} s The value being converted
11020 * @return {String} The comparison value
11022 asText : function(s){
11023 return String(s).replace(this.stripTagsRE, "");
11027 * Strips all HTML tags to sort on text only - Case insensitive
11028 * @param {Mixed} s The value being converted
11029 * @return {String} The comparison value
11031 asUCText : function(s){
11032 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11036 * Case insensitive string
11037 * @param {Mixed} s The value being converted
11038 * @return {String} The comparison value
11040 asUCString : function(s) {
11041 return String(s).toUpperCase();
11046 * @param {Mixed} s The value being converted
11047 * @return {Number} The comparison value
11049 asDate : function(s) {
11053 if(s instanceof Date){
11054 return s.getTime();
11056 return Date.parse(String(s));
11061 * @param {Mixed} s The value being converted
11062 * @return {Float} The comparison value
11064 asFloat : function(s) {
11065 var val = parseFloat(String(s).replace(/,/g, ""));
11074 * @param {Mixed} s The value being converted
11075 * @return {Number} The comparison value
11077 asInt : function(s) {
11078 var val = parseInt(String(s).replace(/,/g, ""));
11086 * Ext JS Library 1.1.1
11087 * Copyright(c) 2006-2007, Ext JS, LLC.
11089 * Originally Released Under LGPL - original licence link has changed is not relivant.
11092 * <script type="text/javascript">
11096 * @class Roo.data.Record
11097 * Instances of this class encapsulate both record <em>definition</em> information, and record
11098 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11099 * to access Records cached in an {@link Roo.data.Store} object.<br>
11101 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11102 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11105 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11107 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11108 * {@link #create}. The parameters are the same.
11109 * @param {Array} data An associative Array of data values keyed by the field name.
11110 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11111 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11112 * not specified an integer id is generated.
11114 Roo.data.Record = function(data, id){
11115 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11120 * Generate a constructor for a specific record layout.
11121 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11122 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11123 * Each field definition object may contain the following properties: <ul>
11124 * <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,
11125 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11126 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11127 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11128 * is being used, then this is a string containing the javascript expression to reference the data relative to
11129 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11130 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11131 * this may be omitted.</p></li>
11132 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11133 * <ul><li>auto (Default, implies no conversion)</li>
11138 * <li>date</li></ul></p></li>
11139 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11140 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11141 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11142 * by the Reader into an object that will be stored in the Record. It is passed the
11143 * following parameters:<ul>
11144 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11146 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11148 * <br>usage:<br><pre><code>
11149 var TopicRecord = Roo.data.Record.create(
11150 {name: 'title', mapping: 'topic_title'},
11151 {name: 'author', mapping: 'username'},
11152 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11153 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11154 {name: 'lastPoster', mapping: 'user2'},
11155 {name: 'excerpt', mapping: 'post_text'}
11158 var myNewRecord = new TopicRecord({
11159 title: 'Do my job please',
11162 lastPost: new Date(),
11163 lastPoster: 'Animal',
11164 excerpt: 'No way dude!'
11166 myStore.add(myNewRecord);
11171 Roo.data.Record.create = function(o){
11172 var f = function(){
11173 f.superclass.constructor.apply(this, arguments);
11175 Roo.extend(f, Roo.data.Record);
11176 var p = f.prototype;
11177 p.fields = new Roo.util.MixedCollection(false, function(field){
11180 for(var i = 0, len = o.length; i < len; i++){
11181 p.fields.add(new Roo.data.Field(o[i]));
11183 f.getField = function(name){
11184 return p.fields.get(name);
11189 Roo.data.Record.AUTO_ID = 1000;
11190 Roo.data.Record.EDIT = 'edit';
11191 Roo.data.Record.REJECT = 'reject';
11192 Roo.data.Record.COMMIT = 'commit';
11194 Roo.data.Record.prototype = {
11196 * Readonly flag - true if this record has been modified.
11205 join : function(store){
11206 this.store = store;
11210 * Set the named field to the specified value.
11211 * @param {String} name The name of the field to set.
11212 * @param {Object} value The value to set the field to.
11214 set : function(name, value){
11215 if(this.data[name] == value){
11219 if(!this.modified){
11220 this.modified = {};
11222 if(typeof this.modified[name] == 'undefined'){
11223 this.modified[name] = this.data[name];
11225 this.data[name] = value;
11226 if(!this.editing && this.store){
11227 this.store.afterEdit(this);
11232 * Get the value of the named field.
11233 * @param {String} name The name of the field to get the value of.
11234 * @return {Object} The value of the field.
11236 get : function(name){
11237 return this.data[name];
11241 beginEdit : function(){
11242 this.editing = true;
11243 this.modified = {};
11247 cancelEdit : function(){
11248 this.editing = false;
11249 delete this.modified;
11253 endEdit : function(){
11254 this.editing = false;
11255 if(this.dirty && this.store){
11256 this.store.afterEdit(this);
11261 * Usually called by the {@link Roo.data.Store} which owns the Record.
11262 * Rejects all changes made to the Record since either creation, or the last commit operation.
11263 * Modified fields are reverted to their original values.
11265 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11266 * of reject operations.
11268 reject : function(){
11269 var m = this.modified;
11271 if(typeof m[n] != "function"){
11272 this.data[n] = m[n];
11275 this.dirty = false;
11276 delete this.modified;
11277 this.editing = false;
11279 this.store.afterReject(this);
11284 * Usually called by the {@link Roo.data.Store} which owns the Record.
11285 * Commits all changes made to the Record since either creation, or the last commit operation.
11287 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11288 * of commit operations.
11290 commit : function(){
11291 this.dirty = false;
11292 delete this.modified;
11293 this.editing = false;
11295 this.store.afterCommit(this);
11300 hasError : function(){
11301 return this.error != null;
11305 clearError : function(){
11310 * Creates a copy of this record.
11311 * @param {String} id (optional) A new record id if you don't want to use this record's id
11314 copy : function(newId) {
11315 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11319 * Ext JS Library 1.1.1
11320 * Copyright(c) 2006-2007, Ext JS, LLC.
11322 * Originally Released Under LGPL - original licence link has changed is not relivant.
11325 * <script type="text/javascript">
11331 * @class Roo.data.Store
11332 * @extends Roo.util.Observable
11333 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11334 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11336 * 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
11337 * has no knowledge of the format of the data returned by the Proxy.<br>
11339 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11340 * instances from the data object. These records are cached and made available through accessor functions.
11342 * Creates a new Store.
11343 * @param {Object} config A config object containing the objects needed for the Store to access data,
11344 * and read the data into Records.
11346 Roo.data.Store = function(config){
11347 this.data = new Roo.util.MixedCollection(false);
11348 this.data.getKey = function(o){
11351 this.baseParams = {};
11353 this.paramNames = {
11358 "multisort" : "_multisort"
11361 if(config && config.data){
11362 this.inlineData = config.data;
11363 delete config.data;
11366 Roo.apply(this, config);
11368 if(this.reader){ // reader passed
11369 this.reader = Roo.factory(this.reader, Roo.data);
11370 this.reader.xmodule = this.xmodule || false;
11371 if(!this.recordType){
11372 this.recordType = this.reader.recordType;
11374 if(this.reader.onMetaChange){
11375 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11379 if(this.recordType){
11380 this.fields = this.recordType.prototype.fields;
11382 this.modified = [];
11386 * @event datachanged
11387 * Fires when the data cache has changed, and a widget which is using this Store
11388 * as a Record cache should refresh its view.
11389 * @param {Store} this
11391 datachanged : true,
11393 * @event metachange
11394 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11395 * @param {Store} this
11396 * @param {Object} meta The JSON metadata
11401 * Fires when Records have been added to the Store
11402 * @param {Store} this
11403 * @param {Roo.data.Record[]} records The array of Records added
11404 * @param {Number} index The index at which the record(s) were added
11409 * Fires when a Record has been removed from the Store
11410 * @param {Store} this
11411 * @param {Roo.data.Record} record The Record that was removed
11412 * @param {Number} index The index at which the record was removed
11417 * Fires when a Record has been updated
11418 * @param {Store} this
11419 * @param {Roo.data.Record} record The Record that was updated
11420 * @param {String} operation The update operation being performed. Value may be one of:
11422 Roo.data.Record.EDIT
11423 Roo.data.Record.REJECT
11424 Roo.data.Record.COMMIT
11430 * Fires when the data cache has been cleared.
11431 * @param {Store} this
11435 * @event beforeload
11436 * Fires before a request is made for a new data object. If the beforeload handler returns false
11437 * the load action will be canceled.
11438 * @param {Store} this
11439 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11443 * @event beforeloadadd
11444 * Fires after a new set of Records has been loaded.
11445 * @param {Store} this
11446 * @param {Roo.data.Record[]} records The Records that were loaded
11447 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11449 beforeloadadd : true,
11452 * Fires after a new set of Records has been loaded, before they are added to the store.
11453 * @param {Store} this
11454 * @param {Roo.data.Record[]} records The Records that were loaded
11455 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11456 * @params {Object} return from reader
11460 * @event loadexception
11461 * Fires if an exception occurs in the Proxy during loading.
11462 * Called with the signature of the Proxy's "loadexception" event.
11463 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11466 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11467 * @param {Object} load options
11468 * @param {Object} jsonData from your request (normally this contains the Exception)
11470 loadexception : true
11474 this.proxy = Roo.factory(this.proxy, Roo.data);
11475 this.proxy.xmodule = this.xmodule || false;
11476 this.relayEvents(this.proxy, ["loadexception"]);
11478 this.sortToggle = {};
11479 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11481 Roo.data.Store.superclass.constructor.call(this);
11483 if(this.inlineData){
11484 this.loadData(this.inlineData);
11485 delete this.inlineData;
11489 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11491 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11492 * without a remote query - used by combo/forms at present.
11496 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11499 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11502 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11503 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11506 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11507 * on any HTTP request
11510 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11513 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11517 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11518 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11520 remoteSort : false,
11523 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11524 * loaded or when a record is removed. (defaults to false).
11526 pruneModifiedRecords : false,
11529 lastOptions : null,
11532 * Add Records to the Store and fires the add event.
11533 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11535 add : function(records){
11536 records = [].concat(records);
11537 for(var i = 0, len = records.length; i < len; i++){
11538 records[i].join(this);
11540 var index = this.data.length;
11541 this.data.addAll(records);
11542 this.fireEvent("add", this, records, index);
11546 * Remove a Record from the Store and fires the remove event.
11547 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11549 remove : function(record){
11550 var index = this.data.indexOf(record);
11551 this.data.removeAt(index);
11553 if(this.pruneModifiedRecords){
11554 this.modified.remove(record);
11556 this.fireEvent("remove", this, record, index);
11560 * Remove all Records from the Store and fires the clear event.
11562 removeAll : function(){
11564 if(this.pruneModifiedRecords){
11565 this.modified = [];
11567 this.fireEvent("clear", this);
11571 * Inserts Records to the Store at the given index and fires the add event.
11572 * @param {Number} index The start index at which to insert the passed Records.
11573 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11575 insert : function(index, records){
11576 records = [].concat(records);
11577 for(var i = 0, len = records.length; i < len; i++){
11578 this.data.insert(index, records[i]);
11579 records[i].join(this);
11581 this.fireEvent("add", this, records, index);
11585 * Get the index within the cache of the passed Record.
11586 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11587 * @return {Number} The index of the passed Record. Returns -1 if not found.
11589 indexOf : function(record){
11590 return this.data.indexOf(record);
11594 * Get the index within the cache of the Record with the passed id.
11595 * @param {String} id The id of the Record to find.
11596 * @return {Number} The index of the Record. Returns -1 if not found.
11598 indexOfId : function(id){
11599 return this.data.indexOfKey(id);
11603 * Get the Record with the specified id.
11604 * @param {String} id The id of the Record to find.
11605 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11607 getById : function(id){
11608 return this.data.key(id);
11612 * Get the Record at the specified index.
11613 * @param {Number} index The index of the Record to find.
11614 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11616 getAt : function(index){
11617 return this.data.itemAt(index);
11621 * Returns a range of Records between specified indices.
11622 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11623 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11624 * @return {Roo.data.Record[]} An array of Records
11626 getRange : function(start, end){
11627 return this.data.getRange(start, end);
11631 storeOptions : function(o){
11632 o = Roo.apply({}, o);
11635 this.lastOptions = o;
11639 * Loads the Record cache from the configured Proxy using the configured Reader.
11641 * If using remote paging, then the first load call must specify the <em>start</em>
11642 * and <em>limit</em> properties in the options.params property to establish the initial
11643 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11645 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11646 * and this call will return before the new data has been loaded. Perform any post-processing
11647 * in a callback function, or in a "load" event handler.</strong>
11649 * @param {Object} options An object containing properties which control loading options:<ul>
11650 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11651 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11652 * passed the following arguments:<ul>
11653 * <li>r : Roo.data.Record[]</li>
11654 * <li>options: Options object from the load call</li>
11655 * <li>success: Boolean success indicator</li></ul></li>
11656 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11657 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11660 load : function(options){
11661 options = options || {};
11662 if(this.fireEvent("beforeload", this, options) !== false){
11663 this.storeOptions(options);
11664 var p = Roo.apply(options.params || {}, this.baseParams);
11665 // if meta was not loaded from remote source.. try requesting it.
11666 if (!this.reader.metaFromRemote) {
11667 p._requestMeta = 1;
11669 if(this.sortInfo && this.remoteSort){
11670 var pn = this.paramNames;
11671 p[pn["sort"]] = this.sortInfo.field;
11672 p[pn["dir"]] = this.sortInfo.direction;
11674 if (this.multiSort) {
11675 var pn = this.paramNames;
11676 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11679 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11684 * Reloads the Record cache from the configured Proxy using the configured Reader and
11685 * the options from the last load operation performed.
11686 * @param {Object} options (optional) An object containing properties which may override the options
11687 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11688 * the most recently used options are reused).
11690 reload : function(options){
11691 this.load(Roo.applyIf(options||{}, this.lastOptions));
11695 // Called as a callback by the Reader during a load operation.
11696 loadRecords : function(o, options, success){
11697 if(!o || success === false){
11698 if(success !== false){
11699 this.fireEvent("load", this, [], options, o);
11701 if(options.callback){
11702 options.callback.call(options.scope || this, [], options, false);
11706 // if data returned failure - throw an exception.
11707 if (o.success === false) {
11708 // show a message if no listener is registered.
11709 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11710 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11712 // loadmask wil be hooked into this..
11713 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11716 var r = o.records, t = o.totalRecords || r.length;
11718 this.fireEvent("beforeloadadd", this, r, options, o);
11720 if(!options || options.add !== true){
11721 if(this.pruneModifiedRecords){
11722 this.modified = [];
11724 for(var i = 0, len = r.length; i < len; i++){
11728 this.data = this.snapshot;
11729 delete this.snapshot;
11732 this.data.addAll(r);
11733 this.totalLength = t;
11735 this.fireEvent("datachanged", this);
11737 this.totalLength = Math.max(t, this.data.length+r.length);
11741 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11743 var e = new Roo.data.Record({});
11745 e.set(this.parent.displayField, this.parent.emptyTitle);
11746 e.set(this.parent.valueField, '');
11751 this.fireEvent("load", this, r, options, o);
11752 if(options.callback){
11753 options.callback.call(options.scope || this, r, options, true);
11759 * Loads data from a passed data block. A Reader which understands the format of the data
11760 * must have been configured in the constructor.
11761 * @param {Object} data The data block from which to read the Records. The format of the data expected
11762 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11763 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11765 loadData : function(o, append){
11766 var r = this.reader.readRecords(o);
11767 this.loadRecords(r, {add: append}, true);
11771 * Gets the number of cached records.
11773 * <em>If using paging, this may not be the total size of the dataset. If the data object
11774 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11775 * the data set size</em>
11777 getCount : function(){
11778 return this.data.length || 0;
11782 * Gets the total number of records in the dataset as returned by the server.
11784 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11785 * the dataset size</em>
11787 getTotalCount : function(){
11788 return this.totalLength || 0;
11792 * Returns the sort state of the Store as an object with two properties:
11794 field {String} The name of the field by which the Records are sorted
11795 direction {String} The sort order, "ASC" or "DESC"
11798 getSortState : function(){
11799 return this.sortInfo;
11803 applySort : function(){
11804 if(this.sortInfo && !this.remoteSort){
11805 var s = this.sortInfo, f = s.field;
11806 var st = this.fields.get(f).sortType;
11807 var fn = function(r1, r2){
11808 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11809 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11811 this.data.sort(s.direction, fn);
11812 if(this.snapshot && this.snapshot != this.data){
11813 this.snapshot.sort(s.direction, fn);
11819 * Sets the default sort column and order to be used by the next load operation.
11820 * @param {String} fieldName The name of the field to sort by.
11821 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11823 setDefaultSort : function(field, dir){
11824 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11828 * Sort the Records.
11829 * If remote sorting is used, the sort is performed on the server, and the cache is
11830 * reloaded. If local sorting is used, the cache is sorted internally.
11831 * @param {String} fieldName The name of the field to sort by.
11832 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11834 sort : function(fieldName, dir){
11835 var f = this.fields.get(fieldName);
11837 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11839 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11840 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11845 this.sortToggle[f.name] = dir;
11846 this.sortInfo = {field: f.name, direction: dir};
11847 if(!this.remoteSort){
11849 this.fireEvent("datachanged", this);
11851 this.load(this.lastOptions);
11856 * Calls the specified function for each of the Records in the cache.
11857 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11858 * Returning <em>false</em> aborts and exits the iteration.
11859 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11861 each : function(fn, scope){
11862 this.data.each(fn, scope);
11866 * Gets all records modified since the last commit. Modified records are persisted across load operations
11867 * (e.g., during paging).
11868 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11870 getModifiedRecords : function(){
11871 return this.modified;
11875 createFilterFn : function(property, value, anyMatch){
11876 if(!value.exec){ // not a regex
11877 value = String(value);
11878 if(value.length == 0){
11881 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11883 return function(r){
11884 return value.test(r.data[property]);
11889 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11890 * @param {String} property A field on your records
11891 * @param {Number} start The record index to start at (defaults to 0)
11892 * @param {Number} end The last record index to include (defaults to length - 1)
11893 * @return {Number} The sum
11895 sum : function(property, start, end){
11896 var rs = this.data.items, v = 0;
11897 start = start || 0;
11898 end = (end || end === 0) ? end : rs.length-1;
11900 for(var i = start; i <= end; i++){
11901 v += (rs[i].data[property] || 0);
11907 * Filter the records by a specified property.
11908 * @param {String} field A field on your records
11909 * @param {String/RegExp} value Either a string that the field
11910 * should start with or a RegExp to test against the field
11911 * @param {Boolean} anyMatch True to match any part not just the beginning
11913 filter : function(property, value, anyMatch){
11914 var fn = this.createFilterFn(property, value, anyMatch);
11915 return fn ? this.filterBy(fn) : this.clearFilter();
11919 * Filter by a function. The specified function will be called with each
11920 * record in this data source. If the function returns true the record is included,
11921 * otherwise it is filtered.
11922 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11923 * @param {Object} scope (optional) The scope of the function (defaults to this)
11925 filterBy : function(fn, scope){
11926 this.snapshot = this.snapshot || this.data;
11927 this.data = this.queryBy(fn, scope||this);
11928 this.fireEvent("datachanged", this);
11932 * Query the records by a specified property.
11933 * @param {String} field A field on your records
11934 * @param {String/RegExp} value Either a string that the field
11935 * should start with or a RegExp to test against the field
11936 * @param {Boolean} anyMatch True to match any part not just the beginning
11937 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11939 query : function(property, value, anyMatch){
11940 var fn = this.createFilterFn(property, value, anyMatch);
11941 return fn ? this.queryBy(fn) : this.data.clone();
11945 * Query by a function. The specified function will be called with each
11946 * record in this data source. If the function returns true the record is included
11948 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11949 * @param {Object} scope (optional) The scope of the function (defaults to this)
11950 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11952 queryBy : function(fn, scope){
11953 var data = this.snapshot || this.data;
11954 return data.filterBy(fn, scope||this);
11958 * Collects unique values for a particular dataIndex from this store.
11959 * @param {String} dataIndex The property to collect
11960 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11961 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11962 * @return {Array} An array of the unique values
11964 collect : function(dataIndex, allowNull, bypassFilter){
11965 var d = (bypassFilter === true && this.snapshot) ?
11966 this.snapshot.items : this.data.items;
11967 var v, sv, r = [], l = {};
11968 for(var i = 0, len = d.length; i < len; i++){
11969 v = d[i].data[dataIndex];
11971 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11980 * Revert to a view of the Record cache with no filtering applied.
11981 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11983 clearFilter : function(suppressEvent){
11984 if(this.snapshot && this.snapshot != this.data){
11985 this.data = this.snapshot;
11986 delete this.snapshot;
11987 if(suppressEvent !== true){
11988 this.fireEvent("datachanged", this);
11994 afterEdit : function(record){
11995 if(this.modified.indexOf(record) == -1){
11996 this.modified.push(record);
11998 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12002 afterReject : function(record){
12003 this.modified.remove(record);
12004 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12008 afterCommit : function(record){
12009 this.modified.remove(record);
12010 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12014 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12015 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12017 commitChanges : function(){
12018 var m = this.modified.slice(0);
12019 this.modified = [];
12020 for(var i = 0, len = m.length; i < len; i++){
12026 * Cancel outstanding changes on all changed records.
12028 rejectChanges : function(){
12029 var m = this.modified.slice(0);
12030 this.modified = [];
12031 for(var i = 0, len = m.length; i < len; i++){
12036 onMetaChange : function(meta, rtype, o){
12037 this.recordType = rtype;
12038 this.fields = rtype.prototype.fields;
12039 delete this.snapshot;
12040 this.sortInfo = meta.sortInfo || this.sortInfo;
12041 this.modified = [];
12042 this.fireEvent('metachange', this, this.reader.meta);
12045 moveIndex : function(data, type)
12047 var index = this.indexOf(data);
12049 var newIndex = index + type;
12053 this.insert(newIndex, data);
12058 * Ext JS Library 1.1.1
12059 * Copyright(c) 2006-2007, Ext JS, LLC.
12061 * Originally Released Under LGPL - original licence link has changed is not relivant.
12064 * <script type="text/javascript">
12068 * @class Roo.data.SimpleStore
12069 * @extends Roo.data.Store
12070 * Small helper class to make creating Stores from Array data easier.
12071 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12072 * @cfg {Array} fields An array of field definition objects, or field name strings.
12073 * @cfg {Array} data The multi-dimensional array of data
12075 * @param {Object} config
12077 Roo.data.SimpleStore = function(config){
12078 Roo.data.SimpleStore.superclass.constructor.call(this, {
12080 reader: new Roo.data.ArrayReader({
12083 Roo.data.Record.create(config.fields)
12085 proxy : new Roo.data.MemoryProxy(config.data)
12089 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12091 * Ext JS Library 1.1.1
12092 * Copyright(c) 2006-2007, Ext JS, LLC.
12094 * Originally Released Under LGPL - original licence link has changed is not relivant.
12097 * <script type="text/javascript">
12102 * @extends Roo.data.Store
12103 * @class Roo.data.JsonStore
12104 * Small helper class to make creating Stores for JSON data easier. <br/>
12106 var store = new Roo.data.JsonStore({
12107 url: 'get-images.php',
12109 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12112 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12113 * JsonReader and HttpProxy (unless inline data is provided).</b>
12114 * @cfg {Array} fields An array of field definition objects, or field name strings.
12116 * @param {Object} config
12118 Roo.data.JsonStore = function(c){
12119 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12120 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12121 reader: new Roo.data.JsonReader(c, c.fields)
12124 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12126 * Ext JS Library 1.1.1
12127 * Copyright(c) 2006-2007, Ext JS, LLC.
12129 * Originally Released Under LGPL - original licence link has changed is not relivant.
12132 * <script type="text/javascript">
12136 Roo.data.Field = function(config){
12137 if(typeof config == "string"){
12138 config = {name: config};
12140 Roo.apply(this, config);
12143 this.type = "auto";
12146 var st = Roo.data.SortTypes;
12147 // named sortTypes are supported, here we look them up
12148 if(typeof this.sortType == "string"){
12149 this.sortType = st[this.sortType];
12152 // set default sortType for strings and dates
12153 if(!this.sortType){
12156 this.sortType = st.asUCString;
12159 this.sortType = st.asDate;
12162 this.sortType = st.none;
12167 var stripRe = /[\$,%]/g;
12169 // prebuilt conversion function for this field, instead of
12170 // switching every time we're reading a value
12172 var cv, dateFormat = this.dateFormat;
12177 cv = function(v){ return v; };
12180 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12184 return v !== undefined && v !== null && v !== '' ?
12185 parseInt(String(v).replace(stripRe, ""), 10) : '';
12190 return v !== undefined && v !== null && v !== '' ?
12191 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12196 cv = function(v){ return v === true || v === "true" || v == 1; };
12203 if(v instanceof Date){
12207 if(dateFormat == "timestamp"){
12208 return new Date(v*1000);
12210 return Date.parseDate(v, dateFormat);
12212 var parsed = Date.parse(v);
12213 return parsed ? new Date(parsed) : null;
12222 Roo.data.Field.prototype = {
12230 * Ext JS Library 1.1.1
12231 * Copyright(c) 2006-2007, Ext JS, LLC.
12233 * Originally Released Under LGPL - original licence link has changed is not relivant.
12236 * <script type="text/javascript">
12239 // Base class for reading structured data from a data source. This class is intended to be
12240 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12243 * @class Roo.data.DataReader
12244 * Base class for reading structured data from a data source. This class is intended to be
12245 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12248 Roo.data.DataReader = function(meta, recordType){
12252 this.recordType = recordType instanceof Array ?
12253 Roo.data.Record.create(recordType) : recordType;
12256 Roo.data.DataReader.prototype = {
12258 * Create an empty record
12259 * @param {Object} data (optional) - overlay some values
12260 * @return {Roo.data.Record} record created.
12262 newRow : function(d) {
12264 this.recordType.prototype.fields.each(function(c) {
12266 case 'int' : da[c.name] = 0; break;
12267 case 'date' : da[c.name] = new Date(); break;
12268 case 'float' : da[c.name] = 0.0; break;
12269 case 'boolean' : da[c.name] = false; break;
12270 default : da[c.name] = ""; break;
12274 return new this.recordType(Roo.apply(da, d));
12279 * Ext JS Library 1.1.1
12280 * Copyright(c) 2006-2007, Ext JS, LLC.
12282 * Originally Released Under LGPL - original licence link has changed is not relivant.
12285 * <script type="text/javascript">
12289 * @class Roo.data.DataProxy
12290 * @extends Roo.data.Observable
12291 * This class is an abstract base class for implementations which provide retrieval of
12292 * unformatted data objects.<br>
12294 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12295 * (of the appropriate type which knows how to parse the data object) to provide a block of
12296 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12298 * Custom implementations must implement the load method as described in
12299 * {@link Roo.data.HttpProxy#load}.
12301 Roo.data.DataProxy = function(){
12304 * @event beforeload
12305 * Fires before a network request is made to retrieve a data object.
12306 * @param {Object} This DataProxy object.
12307 * @param {Object} params The params parameter to the load function.
12312 * Fires before the load method's callback is called.
12313 * @param {Object} This DataProxy object.
12314 * @param {Object} o The data object.
12315 * @param {Object} arg The callback argument object passed to the load function.
12319 * @event loadexception
12320 * Fires if an Exception occurs during data retrieval.
12321 * @param {Object} This DataProxy object.
12322 * @param {Object} o The data object.
12323 * @param {Object} arg The callback argument object passed to the load function.
12324 * @param {Object} e The Exception.
12326 loadexception : true
12328 Roo.data.DataProxy.superclass.constructor.call(this);
12331 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12334 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12338 * Ext JS Library 1.1.1
12339 * Copyright(c) 2006-2007, Ext JS, LLC.
12341 * Originally Released Under LGPL - original licence link has changed is not relivant.
12344 * <script type="text/javascript">
12347 * @class Roo.data.MemoryProxy
12348 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12349 * to the Reader when its load method is called.
12351 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12353 Roo.data.MemoryProxy = function(data){
12357 Roo.data.MemoryProxy.superclass.constructor.call(this);
12361 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12364 * Load data from the requested source (in this case an in-memory
12365 * data object passed to the constructor), read the data object into
12366 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12367 * process that block using the passed callback.
12368 * @param {Object} params This parameter is not used by the MemoryProxy class.
12369 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12370 * object into a block of Roo.data.Records.
12371 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12372 * The function must be passed <ul>
12373 * <li>The Record block object</li>
12374 * <li>The "arg" argument from the load function</li>
12375 * <li>A boolean success indicator</li>
12377 * @param {Object} scope The scope in which to call the callback
12378 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12380 load : function(params, reader, callback, scope, arg){
12381 params = params || {};
12384 result = reader.readRecords(this.data);
12386 this.fireEvent("loadexception", this, arg, null, e);
12387 callback.call(scope, null, arg, false);
12390 callback.call(scope, result, arg, true);
12394 update : function(params, records){
12399 * Ext JS Library 1.1.1
12400 * Copyright(c) 2006-2007, Ext JS, LLC.
12402 * Originally Released Under LGPL - original licence link has changed is not relivant.
12405 * <script type="text/javascript">
12408 * @class Roo.data.HttpProxy
12409 * @extends Roo.data.DataProxy
12410 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12411 * configured to reference a certain URL.<br><br>
12413 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12414 * from which the running page was served.<br><br>
12416 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12418 * Be aware that to enable the browser to parse an XML document, the server must set
12419 * the Content-Type header in the HTTP response to "text/xml".
12421 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12422 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12423 * will be used to make the request.
12425 Roo.data.HttpProxy = function(conn){
12426 Roo.data.HttpProxy.superclass.constructor.call(this);
12427 // is conn a conn config or a real conn?
12429 this.useAjax = !conn || !conn.events;
12433 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12434 // thse are take from connection...
12437 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12440 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12441 * extra parameters to each request made by this object. (defaults to undefined)
12444 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12445 * to each request made by this object. (defaults to undefined)
12448 * @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)
12451 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12454 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12460 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12464 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12465 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12466 * a finer-grained basis than the DataProxy events.
12468 getConnection : function(){
12469 return this.useAjax ? Roo.Ajax : this.conn;
12473 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12474 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12475 * process that block using the passed callback.
12476 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12477 * for the request to the remote server.
12478 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12479 * object into a block of Roo.data.Records.
12480 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12481 * The function must be passed <ul>
12482 * <li>The Record block object</li>
12483 * <li>The "arg" argument from the load function</li>
12484 * <li>A boolean success indicator</li>
12486 * @param {Object} scope The scope in which to call the callback
12487 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12489 load : function(params, reader, callback, scope, arg){
12490 if(this.fireEvent("beforeload", this, params) !== false){
12492 params : params || {},
12494 callback : callback,
12499 callback : this.loadResponse,
12503 Roo.applyIf(o, this.conn);
12504 if(this.activeRequest){
12505 Roo.Ajax.abort(this.activeRequest);
12507 this.activeRequest = Roo.Ajax.request(o);
12509 this.conn.request(o);
12512 callback.call(scope||this, null, arg, false);
12517 loadResponse : function(o, success, response){
12518 delete this.activeRequest;
12520 this.fireEvent("loadexception", this, o, response);
12521 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12526 result = o.reader.read(response);
12528 this.fireEvent("loadexception", this, o, response, e);
12529 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12533 this.fireEvent("load", this, o, o.request.arg);
12534 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12538 update : function(dataSet){
12543 updateResponse : function(dataSet){
12548 * Ext JS Library 1.1.1
12549 * Copyright(c) 2006-2007, Ext JS, LLC.
12551 * Originally Released Under LGPL - original licence link has changed is not relivant.
12554 * <script type="text/javascript">
12558 * @class Roo.data.ScriptTagProxy
12559 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12560 * other than the originating domain of the running page.<br><br>
12562 * <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
12563 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12565 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12566 * source code that is used as the source inside a <script> tag.<br><br>
12568 * In order for the browser to process the returned data, the server must wrap the data object
12569 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12570 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12571 * depending on whether the callback name was passed:
12574 boolean scriptTag = false;
12575 String cb = request.getParameter("callback");
12578 response.setContentType("text/javascript");
12580 response.setContentType("application/x-json");
12582 Writer out = response.getWriter();
12584 out.write(cb + "(");
12586 out.print(dataBlock.toJsonString());
12593 * @param {Object} config A configuration object.
12595 Roo.data.ScriptTagProxy = function(config){
12596 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12597 Roo.apply(this, config);
12598 this.head = document.getElementsByTagName("head")[0];
12601 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12603 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12605 * @cfg {String} url The URL from which to request the data object.
12608 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12612 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12613 * the server the name of the callback function set up by the load call to process the returned data object.
12614 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12615 * javascript output which calls this named function passing the data object as its only parameter.
12617 callbackParam : "callback",
12619 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12620 * name to the request.
12625 * Load data from the configured URL, read the data object into
12626 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12627 * process that block using the passed callback.
12628 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12629 * for the request to the remote server.
12630 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12631 * object into a block of Roo.data.Records.
12632 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12633 * The function must be passed <ul>
12634 * <li>The Record block object</li>
12635 * <li>The "arg" argument from the load function</li>
12636 * <li>A boolean success indicator</li>
12638 * @param {Object} scope The scope in which to call the callback
12639 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12641 load : function(params, reader, callback, scope, arg){
12642 if(this.fireEvent("beforeload", this, params) !== false){
12644 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12646 var url = this.url;
12647 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12649 url += "&_dc=" + (new Date().getTime());
12651 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12654 cb : "stcCallback"+transId,
12655 scriptId : "stcScript"+transId,
12659 callback : callback,
12665 window[trans.cb] = function(o){
12666 conn.handleResponse(o, trans);
12669 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12671 if(this.autoAbort !== false){
12675 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12677 var script = document.createElement("script");
12678 script.setAttribute("src", url);
12679 script.setAttribute("type", "text/javascript");
12680 script.setAttribute("id", trans.scriptId);
12681 this.head.appendChild(script);
12683 this.trans = trans;
12685 callback.call(scope||this, null, arg, false);
12690 isLoading : function(){
12691 return this.trans ? true : false;
12695 * Abort the current server request.
12697 abort : function(){
12698 if(this.isLoading()){
12699 this.destroyTrans(this.trans);
12704 destroyTrans : function(trans, isLoaded){
12705 this.head.removeChild(document.getElementById(trans.scriptId));
12706 clearTimeout(trans.timeoutId);
12708 window[trans.cb] = undefined;
12710 delete window[trans.cb];
12713 // if hasn't been loaded, wait for load to remove it to prevent script error
12714 window[trans.cb] = function(){
12715 window[trans.cb] = undefined;
12717 delete window[trans.cb];
12724 handleResponse : function(o, trans){
12725 this.trans = false;
12726 this.destroyTrans(trans, true);
12729 result = trans.reader.readRecords(o);
12731 this.fireEvent("loadexception", this, o, trans.arg, e);
12732 trans.callback.call(trans.scope||window, null, trans.arg, false);
12735 this.fireEvent("load", this, o, trans.arg);
12736 trans.callback.call(trans.scope||window, result, trans.arg, true);
12740 handleFailure : function(trans){
12741 this.trans = false;
12742 this.destroyTrans(trans, false);
12743 this.fireEvent("loadexception", this, null, trans.arg);
12744 trans.callback.call(trans.scope||window, null, trans.arg, false);
12748 * Ext JS Library 1.1.1
12749 * Copyright(c) 2006-2007, Ext JS, LLC.
12751 * Originally Released Under LGPL - original licence link has changed is not relivant.
12754 * <script type="text/javascript">
12758 * @class Roo.data.JsonReader
12759 * @extends Roo.data.DataReader
12760 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12761 * based on mappings in a provided Roo.data.Record constructor.
12763 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12764 * in the reply previously.
12769 var RecordDef = Roo.data.Record.create([
12770 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12771 {name: 'occupation'} // This field will use "occupation" as the mapping.
12773 var myReader = new Roo.data.JsonReader({
12774 totalProperty: "results", // The property which contains the total dataset size (optional)
12775 root: "rows", // The property which contains an Array of row objects
12776 id: "id" // The property within each row object that provides an ID for the record (optional)
12780 * This would consume a JSON file like this:
12782 { 'results': 2, 'rows': [
12783 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12784 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12787 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12788 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12789 * paged from the remote server.
12790 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12791 * @cfg {String} root name of the property which contains the Array of row objects.
12792 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12793 * @cfg {Array} fields Array of field definition objects
12795 * Create a new JsonReader
12796 * @param {Object} meta Metadata configuration options
12797 * @param {Object} recordType Either an Array of field definition objects,
12798 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12800 Roo.data.JsonReader = function(meta, recordType){
12803 // set some defaults:
12804 Roo.applyIf(meta, {
12805 totalProperty: 'total',
12806 successProperty : 'success',
12811 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12813 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12816 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12817 * Used by Store query builder to append _requestMeta to params.
12820 metaFromRemote : false,
12822 * This method is only used by a DataProxy which has retrieved data from a remote server.
12823 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12824 * @return {Object} data A data block which is used by an Roo.data.Store object as
12825 * a cache of Roo.data.Records.
12827 read : function(response){
12828 var json = response.responseText;
12830 var o = /* eval:var:o */ eval("("+json+")");
12832 throw {message: "JsonReader.read: Json object not found"};
12838 this.metaFromRemote = true;
12839 this.meta = o.metaData;
12840 this.recordType = Roo.data.Record.create(o.metaData.fields);
12841 this.onMetaChange(this.meta, this.recordType, o);
12843 return this.readRecords(o);
12846 // private function a store will implement
12847 onMetaChange : function(meta, recordType, o){
12854 simpleAccess: function(obj, subsc) {
12861 getJsonAccessor: function(){
12863 return function(expr) {
12865 return(re.test(expr))
12866 ? new Function("obj", "return obj." + expr)
12871 return Roo.emptyFn;
12876 * Create a data block containing Roo.data.Records from an XML document.
12877 * @param {Object} o An object which contains an Array of row objects in the property specified
12878 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12879 * which contains the total size of the dataset.
12880 * @return {Object} data A data block which is used by an Roo.data.Store object as
12881 * a cache of Roo.data.Records.
12883 readRecords : function(o){
12885 * After any data loads, the raw JSON data is available for further custom processing.
12889 var s = this.meta, Record = this.recordType,
12890 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12892 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12894 if(s.totalProperty) {
12895 this.getTotal = this.getJsonAccessor(s.totalProperty);
12897 if(s.successProperty) {
12898 this.getSuccess = this.getJsonAccessor(s.successProperty);
12900 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12902 var g = this.getJsonAccessor(s.id);
12903 this.getId = function(rec) {
12905 return (r === undefined || r === "") ? null : r;
12908 this.getId = function(){return null;};
12911 for(var jj = 0; jj < fl; jj++){
12913 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12914 this.ef[jj] = this.getJsonAccessor(map);
12918 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12919 if(s.totalProperty){
12920 var vt = parseInt(this.getTotal(o), 10);
12925 if(s.successProperty){
12926 var vs = this.getSuccess(o);
12927 if(vs === false || vs === 'false'){
12932 for(var i = 0; i < c; i++){
12935 var id = this.getId(n);
12936 for(var j = 0; j < fl; j++){
12938 var v = this.ef[j](n);
12940 Roo.log('missing convert for ' + f.name);
12944 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12946 var record = new Record(values, id);
12948 records[i] = record;
12954 totalRecords : totalRecords
12959 * Ext JS Library 1.1.1
12960 * Copyright(c) 2006-2007, Ext JS, LLC.
12962 * Originally Released Under LGPL - original licence link has changed is not relivant.
12965 * <script type="text/javascript">
12969 * @class Roo.data.ArrayReader
12970 * @extends Roo.data.DataReader
12971 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12972 * Each element of that Array represents a row of data fields. The
12973 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12974 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12978 var RecordDef = Roo.data.Record.create([
12979 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12980 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12982 var myReader = new Roo.data.ArrayReader({
12983 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12987 * This would consume an Array like this:
12989 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12991 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12993 * Create a new JsonReader
12994 * @param {Object} meta Metadata configuration options.
12995 * @param {Object} recordType Either an Array of field definition objects
12996 * as specified to {@link Roo.data.Record#create},
12997 * or an {@link Roo.data.Record} object
12998 * created using {@link Roo.data.Record#create}.
13000 Roo.data.ArrayReader = function(meta, recordType){
13001 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
13004 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13006 * Create a data block containing Roo.data.Records from an XML document.
13007 * @param {Object} o An Array of row objects which represents the dataset.
13008 * @return {Object} data A data block which is used by an Roo.data.Store object as
13009 * a cache of Roo.data.Records.
13011 readRecords : function(o){
13012 var sid = this.meta ? this.meta.id : null;
13013 var recordType = this.recordType, fields = recordType.prototype.fields;
13016 for(var i = 0; i < root.length; i++){
13019 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13020 for(var j = 0, jlen = fields.length; j < jlen; j++){
13021 var f = fields.items[j];
13022 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13023 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13025 values[f.name] = v;
13027 var record = new recordType(values, id);
13029 records[records.length] = record;
13033 totalRecords : records.length
13042 * @class Roo.bootstrap.ComboBox
13043 * @extends Roo.bootstrap.TriggerField
13044 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13045 * @cfg {Boolean} append (true|false) default false
13046 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13047 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13048 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13049 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13050 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13051 * @cfg {Boolean} animate default true
13052 * @cfg {Boolean} emptyResultText only for touch device
13053 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13054 * @cfg {String} emptyTitle default ''
13056 * Create a new ComboBox.
13057 * @param {Object} config Configuration options
13059 Roo.bootstrap.ComboBox = function(config){
13060 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13064 * Fires when the dropdown list is expanded
13065 * @param {Roo.bootstrap.ComboBox} combo This combo box
13070 * Fires when the dropdown list is collapsed
13071 * @param {Roo.bootstrap.ComboBox} combo This combo box
13075 * @event beforeselect
13076 * Fires before a list item is selected. Return false to cancel the selection.
13077 * @param {Roo.bootstrap.ComboBox} combo This combo box
13078 * @param {Roo.data.Record} record The data record returned from the underlying store
13079 * @param {Number} index The index of the selected item in the dropdown list
13081 'beforeselect' : true,
13084 * Fires when a list item is selected
13085 * @param {Roo.bootstrap.ComboBox} combo This combo box
13086 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13087 * @param {Number} index The index of the selected item in the dropdown list
13091 * @event beforequery
13092 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13093 * The event object passed has these properties:
13094 * @param {Roo.bootstrap.ComboBox} combo This combo box
13095 * @param {String} query The query
13096 * @param {Boolean} forceAll true to force "all" query
13097 * @param {Boolean} cancel true to cancel the query
13098 * @param {Object} e The query event object
13100 'beforequery': true,
13103 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13104 * @param {Roo.bootstrap.ComboBox} combo This combo box
13109 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13110 * @param {Roo.bootstrap.ComboBox} combo This combo box
13111 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13116 * Fires when the remove value from the combobox array
13117 * @param {Roo.bootstrap.ComboBox} combo This combo box
13121 * @event afterremove
13122 * Fires when the remove value from the combobox array
13123 * @param {Roo.bootstrap.ComboBox} combo This combo box
13125 'afterremove' : true,
13127 * @event specialfilter
13128 * Fires when specialfilter
13129 * @param {Roo.bootstrap.ComboBox} combo This combo box
13131 'specialfilter' : true,
13134 * Fires when tick the element
13135 * @param {Roo.bootstrap.ComboBox} combo This combo box
13139 * @event touchviewdisplay
13140 * Fires when touch view require special display (default is using displayField)
13141 * @param {Roo.bootstrap.ComboBox} combo This combo box
13142 * @param {Object} cfg set html .
13144 'touchviewdisplay' : true
13149 this.tickItems = [];
13151 this.selectedIndex = -1;
13152 if(this.mode == 'local'){
13153 if(config.queryDelay === undefined){
13154 this.queryDelay = 10;
13156 if(config.minChars === undefined){
13162 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13165 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13166 * rendering into an Roo.Editor, defaults to false)
13169 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13170 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13173 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13176 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13177 * the dropdown list (defaults to undefined, with no header element)
13181 * @cfg {String/Roo.Template} tpl The template to use to render the output
13185 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13187 listWidth: undefined,
13189 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13190 * mode = 'remote' or 'text' if mode = 'local')
13192 displayField: undefined,
13195 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13196 * mode = 'remote' or 'value' if mode = 'local').
13197 * Note: use of a valueField requires the user make a selection
13198 * in order for a value to be mapped.
13200 valueField: undefined,
13202 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13207 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13208 * field's data value (defaults to the underlying DOM element's name)
13210 hiddenName: undefined,
13212 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13216 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13218 selectedClass: 'active',
13221 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13225 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13226 * anchor positions (defaults to 'tl-bl')
13228 listAlign: 'tl-bl?',
13230 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13234 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13235 * query specified by the allQuery config option (defaults to 'query')
13237 triggerAction: 'query',
13239 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13240 * (defaults to 4, does not apply if editable = false)
13244 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13245 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13249 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13250 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13254 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13255 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13259 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13260 * when editable = true (defaults to false)
13262 selectOnFocus:false,
13264 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13266 queryParam: 'query',
13268 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13269 * when mode = 'remote' (defaults to 'Loading...')
13271 loadingText: 'Loading...',
13273 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13277 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13281 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13282 * traditional select (defaults to true)
13286 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13290 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13294 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13295 * listWidth has a higher value)
13299 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13300 * allow the user to set arbitrary text into the field (defaults to false)
13302 forceSelection:false,
13304 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13305 * if typeAhead = true (defaults to 250)
13307 typeAheadDelay : 250,
13309 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13310 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13312 valueNotFoundText : undefined,
13314 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13316 blockFocus : false,
13319 * @cfg {Boolean} disableClear Disable showing of clear button.
13321 disableClear : false,
13323 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13325 alwaysQuery : false,
13328 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13333 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13335 invalidClass : "has-warning",
13338 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13340 validClass : "has-success",
13343 * @cfg {Boolean} specialFilter (true|false) special filter default false
13345 specialFilter : false,
13348 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13350 mobileTouchView : true,
13353 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13355 useNativeIOS : false,
13358 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13360 mobile_restrict_height : false,
13362 ios_options : false,
13374 btnPosition : 'right',
13375 triggerList : true,
13376 showToggleBtn : true,
13378 emptyResultText: 'Empty',
13379 triggerText : 'Select',
13382 // element that contains real text value.. (when hidden is used..)
13384 getAutoCreate : function()
13389 * Render classic select for iso
13392 if(Roo.isIOS && this.useNativeIOS){
13393 cfg = this.getAutoCreateNativeIOS();
13401 if(Roo.isTouch && this.mobileTouchView){
13402 cfg = this.getAutoCreateTouchView();
13409 if(!this.tickable){
13410 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13415 * ComboBox with tickable selections
13418 var align = this.labelAlign || this.parentLabelAlign();
13421 cls : 'form-group roo-combobox-tickable' //input-group
13424 var btn_text_select = '';
13425 var btn_text_done = '';
13426 var btn_text_cancel = '';
13428 if (this.btn_text_show) {
13429 btn_text_select = 'Select';
13430 btn_text_done = 'Done';
13431 btn_text_cancel = 'Cancel';
13436 cls : 'tickable-buttons',
13441 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13442 //html : this.triggerText
13443 html: btn_text_select
13449 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13451 html: btn_text_done
13457 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13459 html: btn_text_cancel
13465 buttons.cn.unshift({
13467 cls: 'roo-select2-search-field-input'
13473 Roo.each(buttons.cn, function(c){
13475 c.cls += ' btn-' + _this.size;
13478 if (_this.disabled) {
13485 style : 'display: contents',
13490 cls: 'form-hidden-field'
13494 cls: 'roo-select2-choices',
13498 cls: 'roo-select2-search-field',
13509 cls: 'roo-select2-container input-group roo-select2-container-multi',
13515 // cls: 'typeahead typeahead-long dropdown-menu',
13516 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13521 if(this.hasFeedback && !this.allowBlank){
13525 cls: 'glyphicon form-control-feedback'
13528 combobox.cn.push(feedback);
13533 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13534 tooltip : 'This field is required'
13536 if (Roo.bootstrap.version == 4) {
13539 style : 'display:none'
13542 if (align ==='left' && this.fieldLabel.length) {
13544 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13551 cls : 'control-label col-form-label',
13552 html : this.fieldLabel
13564 var labelCfg = cfg.cn[1];
13565 var contentCfg = cfg.cn[2];
13568 if(this.indicatorpos == 'right'){
13574 cls : 'control-label col-form-label',
13578 html : this.fieldLabel
13594 labelCfg = cfg.cn[0];
13595 contentCfg = cfg.cn[1];
13599 if(this.labelWidth > 12){
13600 labelCfg.style = "width: " + this.labelWidth + 'px';
13603 if(this.labelWidth < 13 && this.labelmd == 0){
13604 this.labelmd = this.labelWidth;
13607 if(this.labellg > 0){
13608 labelCfg.cls += ' col-lg-' + this.labellg;
13609 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13612 if(this.labelmd > 0){
13613 labelCfg.cls += ' col-md-' + this.labelmd;
13614 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13617 if(this.labelsm > 0){
13618 labelCfg.cls += ' col-sm-' + this.labelsm;
13619 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13622 if(this.labelxs > 0){
13623 labelCfg.cls += ' col-xs-' + this.labelxs;
13624 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13628 } else if ( this.fieldLabel.length) {
13629 // Roo.log(" label");
13634 //cls : 'input-group-addon',
13635 html : this.fieldLabel
13640 if(this.indicatorpos == 'right'){
13644 //cls : 'input-group-addon',
13645 html : this.fieldLabel
13655 // Roo.log(" no label && no align");
13662 ['xs','sm','md','lg'].map(function(size){
13663 if (settings[size]) {
13664 cfg.cls += ' col-' + size + '-' + settings[size];
13672 _initEventsCalled : false,
13675 initEvents: function()
13677 if (this._initEventsCalled) { // as we call render... prevent looping...
13680 this._initEventsCalled = true;
13683 throw "can not find store for combo";
13686 this.indicator = this.indicatorEl();
13688 this.store = Roo.factory(this.store, Roo.data);
13689 this.store.parent = this;
13691 // if we are building from html. then this element is so complex, that we can not really
13692 // use the rendered HTML.
13693 // so we have to trash and replace the previous code.
13694 if (Roo.XComponent.build_from_html) {
13695 // remove this element....
13696 var e = this.el.dom, k=0;
13697 while (e ) { e = e.previousSibling; ++k;}
13702 this.rendered = false;
13704 this.render(this.parent().getChildContainer(true), k);
13707 if(Roo.isIOS && this.useNativeIOS){
13708 this.initIOSView();
13716 if(Roo.isTouch && this.mobileTouchView){
13717 this.initTouchView();
13722 this.initTickableEvents();
13726 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13728 if(this.hiddenName){
13730 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13732 this.hiddenField.dom.value =
13733 this.hiddenValue !== undefined ? this.hiddenValue :
13734 this.value !== undefined ? this.value : '';
13736 // prevent input submission
13737 this.el.dom.removeAttribute('name');
13738 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13743 // this.el.dom.setAttribute('autocomplete', 'off');
13746 var cls = 'x-combo-list';
13748 //this.list = new Roo.Layer({
13749 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13755 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13756 _this.list.setWidth(lw);
13759 this.list.on('mouseover', this.onViewOver, this);
13760 this.list.on('mousemove', this.onViewMove, this);
13761 this.list.on('scroll', this.onViewScroll, this);
13764 this.list.swallowEvent('mousewheel');
13765 this.assetHeight = 0;
13768 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13769 this.assetHeight += this.header.getHeight();
13772 this.innerList = this.list.createChild({cls:cls+'-inner'});
13773 this.innerList.on('mouseover', this.onViewOver, this);
13774 this.innerList.on('mousemove', this.onViewMove, this);
13775 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13777 if(this.allowBlank && !this.pageSize && !this.disableClear){
13778 this.footer = this.list.createChild({cls:cls+'-ft'});
13779 this.pageTb = new Roo.Toolbar(this.footer);
13783 this.footer = this.list.createChild({cls:cls+'-ft'});
13784 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13785 {pageSize: this.pageSize});
13789 if (this.pageTb && this.allowBlank && !this.disableClear) {
13791 this.pageTb.add(new Roo.Toolbar.Fill(), {
13792 cls: 'x-btn-icon x-btn-clear',
13794 handler: function()
13797 _this.clearValue();
13798 _this.onSelect(false, -1);
13803 this.assetHeight += this.footer.getHeight();
13808 this.tpl = Roo.bootstrap.version == 4 ?
13809 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13810 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13813 this.view = new Roo.View(this.list, this.tpl, {
13814 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13816 //this.view.wrapEl.setDisplayed(false);
13817 this.view.on('click', this.onViewClick, this);
13820 this.store.on('beforeload', this.onBeforeLoad, this);
13821 this.store.on('load', this.onLoad, this);
13822 this.store.on('loadexception', this.onLoadException, this);
13824 if(this.resizable){
13825 this.resizer = new Roo.Resizable(this.list, {
13826 pinned:true, handles:'se'
13828 this.resizer.on('resize', function(r, w, h){
13829 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13830 this.listWidth = w;
13831 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13832 this.restrictHeight();
13834 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13837 if(!this.editable){
13838 this.editable = true;
13839 this.setEditable(false);
13844 if (typeof(this.events.add.listeners) != 'undefined') {
13846 this.addicon = this.wrap.createChild(
13847 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13849 this.addicon.on('click', function(e) {
13850 this.fireEvent('add', this);
13853 if (typeof(this.events.edit.listeners) != 'undefined') {
13855 this.editicon = this.wrap.createChild(
13856 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13857 if (this.addicon) {
13858 this.editicon.setStyle('margin-left', '40px');
13860 this.editicon.on('click', function(e) {
13862 // we fire even if inothing is selected..
13863 this.fireEvent('edit', this, this.lastData );
13869 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13870 "up" : function(e){
13871 this.inKeyMode = true;
13875 "down" : function(e){
13876 if(!this.isExpanded()){
13877 this.onTriggerClick();
13879 this.inKeyMode = true;
13884 "enter" : function(e){
13885 // this.onViewClick();
13889 if(this.fireEvent("specialkey", this, e)){
13890 this.onViewClick(false);
13896 "esc" : function(e){
13900 "tab" : function(e){
13903 if(this.fireEvent("specialkey", this, e)){
13904 this.onViewClick(false);
13912 doRelay : function(foo, bar, hname){
13913 if(hname == 'down' || this.scope.isExpanded()){
13914 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13923 this.queryDelay = Math.max(this.queryDelay || 10,
13924 this.mode == 'local' ? 10 : 250);
13927 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13929 if(this.typeAhead){
13930 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13932 if(this.editable !== false){
13933 this.inputEl().on("keyup", this.onKeyUp, this);
13935 if(this.forceSelection){
13936 this.inputEl().on('blur', this.doForce, this);
13940 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13941 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13945 initTickableEvents: function()
13949 if(this.hiddenName){
13951 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13953 this.hiddenField.dom.value =
13954 this.hiddenValue !== undefined ? this.hiddenValue :
13955 this.value !== undefined ? this.value : '';
13957 // prevent input submission
13958 this.el.dom.removeAttribute('name');
13959 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13964 // this.list = this.el.select('ul.dropdown-menu',true).first();
13966 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13967 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13968 if(this.triggerList){
13969 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13972 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13973 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13975 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13976 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13978 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13979 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13981 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13982 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13983 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13986 this.cancelBtn.hide();
13991 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13992 _this.list.setWidth(lw);
13995 this.list.on('mouseover', this.onViewOver, this);
13996 this.list.on('mousemove', this.onViewMove, this);
13998 this.list.on('scroll', this.onViewScroll, this);
14001 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14002 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14005 this.view = new Roo.View(this.list, this.tpl, {
14010 selectedClass: this.selectedClass
14013 //this.view.wrapEl.setDisplayed(false);
14014 this.view.on('click', this.onViewClick, this);
14018 this.store.on('beforeload', this.onBeforeLoad, this);
14019 this.store.on('load', this.onLoad, this);
14020 this.store.on('loadexception', this.onLoadException, this);
14023 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14024 "up" : function(e){
14025 this.inKeyMode = true;
14029 "down" : function(e){
14030 this.inKeyMode = true;
14034 "enter" : function(e){
14035 if(this.fireEvent("specialkey", this, e)){
14036 this.onViewClick(false);
14042 "esc" : function(e){
14043 this.onTickableFooterButtonClick(e, false, false);
14046 "tab" : function(e){
14047 this.fireEvent("specialkey", this, e);
14049 this.onTickableFooterButtonClick(e, false, false);
14056 doRelay : function(e, fn, key){
14057 if(this.scope.isExpanded()){
14058 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14067 this.queryDelay = Math.max(this.queryDelay || 10,
14068 this.mode == 'local' ? 10 : 250);
14071 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14073 if(this.typeAhead){
14074 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14077 if(this.editable !== false){
14078 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14081 this.indicator = this.indicatorEl();
14083 if(this.indicator){
14084 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14085 this.indicator.hide();
14090 onDestroy : function(){
14092 this.view.setStore(null);
14093 this.view.el.removeAllListeners();
14094 this.view.el.remove();
14095 this.view.purgeListeners();
14098 this.list.dom.innerHTML = '';
14102 this.store.un('beforeload', this.onBeforeLoad, this);
14103 this.store.un('load', this.onLoad, this);
14104 this.store.un('loadexception', this.onLoadException, this);
14106 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14110 fireKey : function(e){
14111 if(e.isNavKeyPress() && !this.list.isVisible()){
14112 this.fireEvent("specialkey", this, e);
14117 onResize: function(w, h){
14118 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14120 // if(typeof w != 'number'){
14121 // // we do not handle it!?!?
14124 // var tw = this.trigger.getWidth();
14125 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14126 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14128 // this.inputEl().setWidth( this.adjustWidth('input', x));
14130 // //this.trigger.setStyle('left', x+'px');
14132 // if(this.list && this.listWidth === undefined){
14133 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14134 // this.list.setWidth(lw);
14135 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14143 * Allow or prevent the user from directly editing the field text. If false is passed,
14144 * the user will only be able to select from the items defined in the dropdown list. This method
14145 * is the runtime equivalent of setting the 'editable' config option at config time.
14146 * @param {Boolean} value True to allow the user to directly edit the field text
14148 setEditable : function(value){
14149 if(value == this.editable){
14152 this.editable = value;
14154 this.inputEl().dom.setAttribute('readOnly', true);
14155 this.inputEl().on('mousedown', this.onTriggerClick, this);
14156 this.inputEl().addClass('x-combo-noedit');
14158 this.inputEl().dom.setAttribute('readOnly', false);
14159 this.inputEl().un('mousedown', this.onTriggerClick, this);
14160 this.inputEl().removeClass('x-combo-noedit');
14166 onBeforeLoad : function(combo,opts){
14167 if(!this.hasFocus){
14171 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14173 this.restrictHeight();
14174 this.selectedIndex = -1;
14178 onLoad : function(){
14180 this.hasQuery = false;
14182 if(!this.hasFocus){
14186 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14187 this.loading.hide();
14190 if(this.store.getCount() > 0){
14193 this.restrictHeight();
14194 if(this.lastQuery == this.allQuery){
14195 if(this.editable && !this.tickable){
14196 this.inputEl().dom.select();
14200 !this.selectByValue(this.value, true) &&
14203 !this.store.lastOptions ||
14204 typeof(this.store.lastOptions.add) == 'undefined' ||
14205 this.store.lastOptions.add != true
14208 this.select(0, true);
14211 if(this.autoFocus){
14214 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14215 this.taTask.delay(this.typeAheadDelay);
14219 this.onEmptyResults();
14225 onLoadException : function()
14227 this.hasQuery = false;
14229 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14230 this.loading.hide();
14233 if(this.tickable && this.editable){
14238 // only causes errors at present
14239 //Roo.log(this.store.reader.jsonData);
14240 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14242 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14248 onTypeAhead : function(){
14249 if(this.store.getCount() > 0){
14250 var r = this.store.getAt(0);
14251 var newValue = r.data[this.displayField];
14252 var len = newValue.length;
14253 var selStart = this.getRawValue().length;
14255 if(selStart != len){
14256 this.setRawValue(newValue);
14257 this.selectText(selStart, newValue.length);
14263 onSelect : function(record, index){
14265 if(this.fireEvent('beforeselect', this, record, index) !== false){
14267 this.setFromData(index > -1 ? record.data : false);
14270 this.fireEvent('select', this, record, index);
14275 * Returns the currently selected field value or empty string if no value is set.
14276 * @return {String} value The selected value
14278 getValue : function()
14280 if(Roo.isIOS && this.useNativeIOS){
14281 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14285 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14288 if(this.valueField){
14289 return typeof this.value != 'undefined' ? this.value : '';
14291 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14295 getRawValue : function()
14297 if(Roo.isIOS && this.useNativeIOS){
14298 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14301 var v = this.inputEl().getValue();
14307 * Clears any text/value currently set in the field
14309 clearValue : function(){
14311 if(this.hiddenField){
14312 this.hiddenField.dom.value = '';
14315 this.setRawValue('');
14316 this.lastSelectionText = '';
14317 this.lastData = false;
14319 var close = this.closeTriggerEl();
14330 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14331 * will be displayed in the field. If the value does not match the data value of an existing item,
14332 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14333 * Otherwise the field will be blank (although the value will still be set).
14334 * @param {String} value The value to match
14336 setValue : function(v)
14338 if(Roo.isIOS && this.useNativeIOS){
14339 this.setIOSValue(v);
14349 if(this.valueField){
14350 var r = this.findRecord(this.valueField, v);
14352 text = r.data[this.displayField];
14353 }else if(this.valueNotFoundText !== undefined){
14354 text = this.valueNotFoundText;
14357 this.lastSelectionText = text;
14358 if(this.hiddenField){
14359 this.hiddenField.dom.value = v;
14361 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14364 var close = this.closeTriggerEl();
14367 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14373 * @property {Object} the last set data for the element
14378 * Sets the value of the field based on a object which is related to the record format for the store.
14379 * @param {Object} value the value to set as. or false on reset?
14381 setFromData : function(o){
14388 var dv = ''; // display value
14389 var vv = ''; // value value..
14391 if (this.displayField) {
14392 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14394 // this is an error condition!!!
14395 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14398 if(this.valueField){
14399 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14402 var close = this.closeTriggerEl();
14405 if(dv.length || vv * 1 > 0){
14407 this.blockFocus=true;
14413 if(this.hiddenField){
14414 this.hiddenField.dom.value = vv;
14416 this.lastSelectionText = dv;
14417 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14421 // no hidden field.. - we store the value in 'value', but still display
14422 // display field!!!!
14423 this.lastSelectionText = dv;
14424 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14431 reset : function(){
14432 // overridden so that last data is reset..
14439 this.setValue(this.originalValue);
14440 //this.clearInvalid();
14441 this.lastData = false;
14443 this.view.clearSelections();
14449 findRecord : function(prop, value){
14451 if(this.store.getCount() > 0){
14452 this.store.each(function(r){
14453 if(r.data[prop] == value){
14463 getName: function()
14465 // returns hidden if it's set..
14466 if (!this.rendered) {return ''};
14467 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14471 onViewMove : function(e, t){
14472 this.inKeyMode = false;
14476 onViewOver : function(e, t){
14477 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14480 var item = this.view.findItemFromChild(t);
14483 var index = this.view.indexOf(item);
14484 this.select(index, false);
14489 onViewClick : function(view, doFocus, el, e)
14491 var index = this.view.getSelectedIndexes()[0];
14493 var r = this.store.getAt(index);
14497 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14504 Roo.each(this.tickItems, function(v,k){
14506 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14508 _this.tickItems.splice(k, 1);
14510 if(typeof(e) == 'undefined' && view == false){
14511 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14523 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14524 this.tickItems.push(r.data);
14527 if(typeof(e) == 'undefined' && view == false){
14528 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14535 this.onSelect(r, index);
14537 if(doFocus !== false && !this.blockFocus){
14538 this.inputEl().focus();
14543 restrictHeight : function(){
14544 //this.innerList.dom.style.height = '';
14545 //var inner = this.innerList.dom;
14546 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14547 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14548 //this.list.beginUpdate();
14549 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14550 this.list.alignTo(this.inputEl(), this.listAlign);
14551 this.list.alignTo(this.inputEl(), this.listAlign);
14552 //this.list.endUpdate();
14556 onEmptyResults : function(){
14558 if(this.tickable && this.editable){
14559 this.hasFocus = false;
14560 this.restrictHeight();
14568 * Returns true if the dropdown list is expanded, else false.
14570 isExpanded : function(){
14571 return this.list.isVisible();
14575 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14576 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14577 * @param {String} value The data value of the item to select
14578 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14579 * selected item if it is not currently in view (defaults to true)
14580 * @return {Boolean} True if the value matched an item in the list, else false
14582 selectByValue : function(v, scrollIntoView){
14583 if(v !== undefined && v !== null){
14584 var r = this.findRecord(this.valueField || this.displayField, v);
14586 this.select(this.store.indexOf(r), scrollIntoView);
14594 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14595 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14596 * @param {Number} index The zero-based index of the list item to select
14597 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14598 * selected item if it is not currently in view (defaults to true)
14600 select : function(index, scrollIntoView){
14601 this.selectedIndex = index;
14602 this.view.select(index);
14603 if(scrollIntoView !== false){
14604 var el = this.view.getNode(index);
14606 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14609 this.list.scrollChildIntoView(el, false);
14615 selectNext : function(){
14616 var ct = this.store.getCount();
14618 if(this.selectedIndex == -1){
14620 }else if(this.selectedIndex < ct-1){
14621 this.select(this.selectedIndex+1);
14627 selectPrev : function(){
14628 var ct = this.store.getCount();
14630 if(this.selectedIndex == -1){
14632 }else if(this.selectedIndex != 0){
14633 this.select(this.selectedIndex-1);
14639 onKeyUp : function(e){
14640 if(this.editable !== false && !e.isSpecialKey()){
14641 this.lastKey = e.getKey();
14642 this.dqTask.delay(this.queryDelay);
14647 validateBlur : function(){
14648 return !this.list || !this.list.isVisible();
14652 initQuery : function(){
14654 var v = this.getRawValue();
14656 if(this.tickable && this.editable){
14657 v = this.tickableInputEl().getValue();
14664 doForce : function(){
14665 if(this.inputEl().dom.value.length > 0){
14666 this.inputEl().dom.value =
14667 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14673 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14674 * query allowing the query action to be canceled if needed.
14675 * @param {String} query The SQL query to execute
14676 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14677 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14678 * saved in the current store (defaults to false)
14680 doQuery : function(q, forceAll){
14682 if(q === undefined || q === null){
14687 forceAll: forceAll,
14691 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14696 forceAll = qe.forceAll;
14697 if(forceAll === true || (q.length >= this.minChars)){
14699 this.hasQuery = true;
14701 if(this.lastQuery != q || this.alwaysQuery){
14702 this.lastQuery = q;
14703 if(this.mode == 'local'){
14704 this.selectedIndex = -1;
14706 this.store.clearFilter();
14709 if(this.specialFilter){
14710 this.fireEvent('specialfilter', this);
14715 this.store.filter(this.displayField, q);
14718 this.store.fireEvent("datachanged", this.store);
14725 this.store.baseParams[this.queryParam] = q;
14727 var options = {params : this.getParams(q)};
14730 options.add = true;
14731 options.params.start = this.page * this.pageSize;
14734 this.store.load(options);
14737 * this code will make the page width larger, at the beginning, the list not align correctly,
14738 * we should expand the list on onLoad
14739 * so command out it
14744 this.selectedIndex = -1;
14749 this.loadNext = false;
14753 getParams : function(q){
14755 //p[this.queryParam] = q;
14759 p.limit = this.pageSize;
14765 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14767 collapse : function(){
14768 if(!this.isExpanded()){
14774 this.hasFocus = false;
14778 this.cancelBtn.hide();
14779 this.trigger.show();
14782 this.tickableInputEl().dom.value = '';
14783 this.tickableInputEl().blur();
14788 Roo.get(document).un('mousedown', this.collapseIf, this);
14789 Roo.get(document).un('mousewheel', this.collapseIf, this);
14790 if (!this.editable) {
14791 Roo.get(document).un('keydown', this.listKeyPress, this);
14793 this.fireEvent('collapse', this);
14799 collapseIf : function(e){
14800 var in_combo = e.within(this.el);
14801 var in_list = e.within(this.list);
14802 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14804 if (in_combo || in_list || is_list) {
14805 //e.stopPropagation();
14810 this.onTickableFooterButtonClick(e, false, false);
14818 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14820 expand : function(){
14822 if(this.isExpanded() || !this.hasFocus){
14826 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14827 this.list.setWidth(lw);
14833 this.restrictHeight();
14837 this.tickItems = Roo.apply([], this.item);
14840 this.cancelBtn.show();
14841 this.trigger.hide();
14844 this.tickableInputEl().focus();
14849 Roo.get(document).on('mousedown', this.collapseIf, this);
14850 Roo.get(document).on('mousewheel', this.collapseIf, this);
14851 if (!this.editable) {
14852 Roo.get(document).on('keydown', this.listKeyPress, this);
14855 this.fireEvent('expand', this);
14859 // Implements the default empty TriggerField.onTriggerClick function
14860 onTriggerClick : function(e)
14862 Roo.log('trigger click');
14864 if(this.disabled || !this.triggerList){
14869 this.loadNext = false;
14871 if(this.isExpanded()){
14873 if (!this.blockFocus) {
14874 this.inputEl().focus();
14878 this.hasFocus = true;
14879 if(this.triggerAction == 'all') {
14880 this.doQuery(this.allQuery, true);
14882 this.doQuery(this.getRawValue());
14884 if (!this.blockFocus) {
14885 this.inputEl().focus();
14890 onTickableTriggerClick : function(e)
14897 this.loadNext = false;
14898 this.hasFocus = true;
14900 if(this.triggerAction == 'all') {
14901 this.doQuery(this.allQuery, true);
14903 this.doQuery(this.getRawValue());
14907 onSearchFieldClick : function(e)
14909 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14910 this.onTickableFooterButtonClick(e, false, false);
14914 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14919 this.loadNext = false;
14920 this.hasFocus = true;
14922 if(this.triggerAction == 'all') {
14923 this.doQuery(this.allQuery, true);
14925 this.doQuery(this.getRawValue());
14929 listKeyPress : function(e)
14931 //Roo.log('listkeypress');
14932 // scroll to first matching element based on key pres..
14933 if (e.isSpecialKey()) {
14936 var k = String.fromCharCode(e.getKey()).toUpperCase();
14939 var csel = this.view.getSelectedNodes();
14940 var cselitem = false;
14942 var ix = this.view.indexOf(csel[0]);
14943 cselitem = this.store.getAt(ix);
14944 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14950 this.store.each(function(v) {
14952 // start at existing selection.
14953 if (cselitem.id == v.id) {
14959 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14960 match = this.store.indexOf(v);
14966 if (match === false) {
14967 return true; // no more action?
14970 this.view.select(match);
14971 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14972 sn.scrollIntoView(sn.dom.parentNode, false);
14975 onViewScroll : function(e, t){
14977 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){
14981 this.hasQuery = true;
14983 this.loading = this.list.select('.loading', true).first();
14985 if(this.loading === null){
14986 this.list.createChild({
14988 cls: 'loading roo-select2-more-results roo-select2-active',
14989 html: 'Loading more results...'
14992 this.loading = this.list.select('.loading', true).first();
14994 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14996 this.loading.hide();
14999 this.loading.show();
15004 this.loadNext = true;
15006 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15011 addItem : function(o)
15013 var dv = ''; // display value
15015 if (this.displayField) {
15016 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15018 // this is an error condition!!!
15019 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15026 var choice = this.choices.createChild({
15028 cls: 'roo-select2-search-choice',
15037 cls: 'roo-select2-search-choice-close fa fa-times',
15042 }, this.searchField);
15044 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15046 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15054 this.inputEl().dom.value = '';
15059 onRemoveItem : function(e, _self, o)
15061 e.preventDefault();
15063 this.lastItem = Roo.apply([], this.item);
15065 var index = this.item.indexOf(o.data) * 1;
15068 Roo.log('not this item?!');
15072 this.item.splice(index, 1);
15077 this.fireEvent('remove', this, e);
15083 syncValue : function()
15085 if(!this.item.length){
15092 Roo.each(this.item, function(i){
15093 if(_this.valueField){
15094 value.push(i[_this.valueField]);
15101 this.value = value.join(',');
15103 if(this.hiddenField){
15104 this.hiddenField.dom.value = this.value;
15107 this.store.fireEvent("datachanged", this.store);
15112 clearItem : function()
15114 if(!this.multiple){
15120 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15128 if(this.tickable && !Roo.isTouch){
15129 this.view.refresh();
15133 inputEl: function ()
15135 if(Roo.isIOS && this.useNativeIOS){
15136 return this.el.select('select.roo-ios-select', true).first();
15139 if(Roo.isTouch && this.mobileTouchView){
15140 return this.el.select('input.form-control',true).first();
15144 return this.searchField;
15147 return this.el.select('input.form-control',true).first();
15150 onTickableFooterButtonClick : function(e, btn, el)
15152 e.preventDefault();
15154 this.lastItem = Roo.apply([], this.item);
15156 if(btn && btn.name == 'cancel'){
15157 this.tickItems = Roo.apply([], this.item);
15166 Roo.each(this.tickItems, function(o){
15174 validate : function()
15176 if(this.getVisibilityEl().hasClass('hidden')){
15180 var v = this.getRawValue();
15183 v = this.getValue();
15186 if(this.disabled || this.allowBlank || v.length){
15191 this.markInvalid();
15195 tickableInputEl : function()
15197 if(!this.tickable || !this.editable){
15198 return this.inputEl();
15201 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15205 getAutoCreateTouchView : function()
15210 cls: 'form-group' //input-group
15216 type : this.inputType,
15217 cls : 'form-control x-combo-noedit',
15218 autocomplete: 'new-password',
15219 placeholder : this.placeholder || '',
15224 input.name = this.name;
15228 input.cls += ' input-' + this.size;
15231 if (this.disabled) {
15232 input.disabled = true;
15243 inputblock.cls += ' input-group';
15245 inputblock.cn.unshift({
15247 cls : 'input-group-addon input-group-prepend input-group-text',
15252 if(this.removable && !this.multiple){
15253 inputblock.cls += ' roo-removable';
15255 inputblock.cn.push({
15258 cls : 'roo-combo-removable-btn close'
15262 if(this.hasFeedback && !this.allowBlank){
15264 inputblock.cls += ' has-feedback';
15266 inputblock.cn.push({
15268 cls: 'glyphicon form-control-feedback'
15275 inputblock.cls += (this.before) ? '' : ' input-group';
15277 inputblock.cn.push({
15279 cls : 'input-group-addon input-group-append input-group-text',
15285 var ibwrap = inputblock;
15290 cls: 'roo-select2-choices',
15294 cls: 'roo-select2-search-field',
15307 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15312 cls: 'form-hidden-field'
15318 if(!this.multiple && this.showToggleBtn){
15325 if (this.caret != false) {
15328 cls: 'fa fa-' + this.caret
15335 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15340 cls: 'combobox-clear',
15354 combobox.cls += ' roo-select2-container-multi';
15357 var align = this.labelAlign || this.parentLabelAlign();
15359 if (align ==='left' && this.fieldLabel.length) {
15364 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15365 tooltip : 'This field is required'
15369 cls : 'control-label col-form-label',
15370 html : this.fieldLabel
15381 var labelCfg = cfg.cn[1];
15382 var contentCfg = cfg.cn[2];
15385 if(this.indicatorpos == 'right'){
15390 cls : 'control-label col-form-label',
15394 html : this.fieldLabel
15398 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15399 tooltip : 'This field is required'
15412 labelCfg = cfg.cn[0];
15413 contentCfg = cfg.cn[1];
15418 if(this.labelWidth > 12){
15419 labelCfg.style = "width: " + this.labelWidth + 'px';
15422 if(this.labelWidth < 13 && this.labelmd == 0){
15423 this.labelmd = this.labelWidth;
15426 if(this.labellg > 0){
15427 labelCfg.cls += ' col-lg-' + this.labellg;
15428 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15431 if(this.labelmd > 0){
15432 labelCfg.cls += ' col-md-' + this.labelmd;
15433 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15436 if(this.labelsm > 0){
15437 labelCfg.cls += ' col-sm-' + this.labelsm;
15438 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15441 if(this.labelxs > 0){
15442 labelCfg.cls += ' col-xs-' + this.labelxs;
15443 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15447 } else if ( this.fieldLabel.length) {
15451 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15452 tooltip : 'This field is required'
15456 cls : 'control-label',
15457 html : this.fieldLabel
15468 if(this.indicatorpos == 'right'){
15472 cls : 'control-label',
15473 html : this.fieldLabel,
15477 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15478 tooltip : 'This field is required'
15495 var settings = this;
15497 ['xs','sm','md','lg'].map(function(size){
15498 if (settings[size]) {
15499 cfg.cls += ' col-' + size + '-' + settings[size];
15506 initTouchView : function()
15508 this.renderTouchView();
15510 this.touchViewEl.on('scroll', function(){
15511 this.el.dom.scrollTop = 0;
15514 this.originalValue = this.getValue();
15516 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15518 this.inputEl().on("click", this.showTouchView, this);
15519 if (this.triggerEl) {
15520 this.triggerEl.on("click", this.showTouchView, this);
15524 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15525 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15527 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15529 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15530 this.store.on('load', this.onTouchViewLoad, this);
15531 this.store.on('loadexception', this.onTouchViewLoadException, this);
15533 if(this.hiddenName){
15535 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15537 this.hiddenField.dom.value =
15538 this.hiddenValue !== undefined ? this.hiddenValue :
15539 this.value !== undefined ? this.value : '';
15541 this.el.dom.removeAttribute('name');
15542 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15546 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15547 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15550 if(this.removable && !this.multiple){
15551 var close = this.closeTriggerEl();
15553 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15554 close.on('click', this.removeBtnClick, this, close);
15558 * fix the bug in Safari iOS8
15560 this.inputEl().on("focus", function(e){
15561 document.activeElement.blur();
15564 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15571 renderTouchView : function()
15573 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15574 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15576 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15577 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15579 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15580 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15581 this.touchViewBodyEl.setStyle('overflow', 'auto');
15583 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15584 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15586 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15587 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15591 showTouchView : function()
15597 this.touchViewHeaderEl.hide();
15599 if(this.modalTitle.length){
15600 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15601 this.touchViewHeaderEl.show();
15604 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15605 this.touchViewEl.show();
15607 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15609 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15610 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15612 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15614 if(this.modalTitle.length){
15615 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15618 this.touchViewBodyEl.setHeight(bodyHeight);
15622 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15624 this.touchViewEl.addClass('in');
15627 if(this._touchViewMask){
15628 Roo.get(document.body).addClass("x-body-masked");
15629 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15630 this._touchViewMask.setStyle('z-index', 10000);
15631 this._touchViewMask.addClass('show');
15634 this.doTouchViewQuery();
15638 hideTouchView : function()
15640 this.touchViewEl.removeClass('in');
15644 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15646 this.touchViewEl.setStyle('display', 'none');
15649 if(this._touchViewMask){
15650 this._touchViewMask.removeClass('show');
15651 Roo.get(document.body).removeClass("x-body-masked");
15655 setTouchViewValue : function()
15662 Roo.each(this.tickItems, function(o){
15667 this.hideTouchView();
15670 doTouchViewQuery : function()
15679 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15683 if(!this.alwaysQuery || this.mode == 'local'){
15684 this.onTouchViewLoad();
15691 onTouchViewBeforeLoad : function(combo,opts)
15697 onTouchViewLoad : function()
15699 if(this.store.getCount() < 1){
15700 this.onTouchViewEmptyResults();
15704 this.clearTouchView();
15706 var rawValue = this.getRawValue();
15708 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15710 this.tickItems = [];
15712 this.store.data.each(function(d, rowIndex){
15713 var row = this.touchViewListGroup.createChild(template);
15715 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15716 row.addClass(d.data.cls);
15719 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15722 html : d.data[this.displayField]
15725 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15726 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15729 row.removeClass('selected');
15730 if(!this.multiple && this.valueField &&
15731 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15734 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15735 row.addClass('selected');
15738 if(this.multiple && this.valueField &&
15739 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15743 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15744 this.tickItems.push(d.data);
15747 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15751 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15753 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15755 if(this.modalTitle.length){
15756 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15759 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15761 if(this.mobile_restrict_height && listHeight < bodyHeight){
15762 this.touchViewBodyEl.setHeight(listHeight);
15767 if(firstChecked && listHeight > bodyHeight){
15768 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15773 onTouchViewLoadException : function()
15775 this.hideTouchView();
15778 onTouchViewEmptyResults : function()
15780 this.clearTouchView();
15782 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15784 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15788 clearTouchView : function()
15790 this.touchViewListGroup.dom.innerHTML = '';
15793 onTouchViewClick : function(e, el, o)
15795 e.preventDefault();
15798 var rowIndex = o.rowIndex;
15800 var r = this.store.getAt(rowIndex);
15802 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15804 if(!this.multiple){
15805 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15806 c.dom.removeAttribute('checked');
15809 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15811 this.setFromData(r.data);
15813 var close = this.closeTriggerEl();
15819 this.hideTouchView();
15821 this.fireEvent('select', this, r, rowIndex);
15826 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15827 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15828 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15832 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15833 this.addItem(r.data);
15834 this.tickItems.push(r.data);
15838 getAutoCreateNativeIOS : function()
15841 cls: 'form-group' //input-group,
15846 cls : 'roo-ios-select'
15850 combobox.name = this.name;
15853 if (this.disabled) {
15854 combobox.disabled = true;
15857 var settings = this;
15859 ['xs','sm','md','lg'].map(function(size){
15860 if (settings[size]) {
15861 cfg.cls += ' col-' + size + '-' + settings[size];
15871 initIOSView : function()
15873 this.store.on('load', this.onIOSViewLoad, this);
15878 onIOSViewLoad : function()
15880 if(this.store.getCount() < 1){
15884 this.clearIOSView();
15886 if(this.allowBlank) {
15888 var default_text = '-- SELECT --';
15890 if(this.placeholder.length){
15891 default_text = this.placeholder;
15894 if(this.emptyTitle.length){
15895 default_text += ' - ' + this.emptyTitle + ' -';
15898 var opt = this.inputEl().createChild({
15901 html : default_text
15905 o[this.valueField] = 0;
15906 o[this.displayField] = default_text;
15908 this.ios_options.push({
15915 this.store.data.each(function(d, rowIndex){
15919 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15920 html = d.data[this.displayField];
15925 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15926 value = d.data[this.valueField];
15935 if(this.value == d.data[this.valueField]){
15936 option['selected'] = true;
15939 var opt = this.inputEl().createChild(option);
15941 this.ios_options.push({
15948 this.inputEl().on('change', function(){
15949 this.fireEvent('select', this);
15954 clearIOSView: function()
15956 this.inputEl().dom.innerHTML = '';
15958 this.ios_options = [];
15961 setIOSValue: function(v)
15965 if(!this.ios_options){
15969 Roo.each(this.ios_options, function(opts){
15971 opts.el.dom.removeAttribute('selected');
15973 if(opts.data[this.valueField] != v){
15977 opts.el.dom.setAttribute('selected', true);
15983 * @cfg {Boolean} grow
15987 * @cfg {Number} growMin
15991 * @cfg {Number} growMax
16000 Roo.apply(Roo.bootstrap.ComboBox, {
16004 cls: 'modal-header',
16026 cls: 'list-group-item',
16030 cls: 'roo-combobox-list-group-item-value'
16034 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16048 listItemCheckbox : {
16050 cls: 'list-group-item',
16054 cls: 'roo-combobox-list-group-item-value'
16058 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16074 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16079 cls: 'modal-footer',
16087 cls: 'col-xs-6 text-left',
16090 cls: 'btn btn-danger roo-touch-view-cancel',
16096 cls: 'col-xs-6 text-right',
16099 cls: 'btn btn-success roo-touch-view-ok',
16110 Roo.apply(Roo.bootstrap.ComboBox, {
16112 touchViewTemplate : {
16114 cls: 'modal fade roo-combobox-touch-view',
16118 cls: 'modal-dialog',
16119 style : 'position:fixed', // we have to fix position....
16123 cls: 'modal-content',
16125 Roo.bootstrap.ComboBox.header,
16126 Roo.bootstrap.ComboBox.body,
16127 Roo.bootstrap.ComboBox.footer
16136 * Ext JS Library 1.1.1
16137 * Copyright(c) 2006-2007, Ext JS, LLC.
16139 * Originally Released Under LGPL - original licence link has changed is not relivant.
16142 * <script type="text/javascript">
16147 * @extends Roo.util.Observable
16148 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16149 * This class also supports single and multi selection modes. <br>
16150 * Create a data model bound view:
16152 var store = new Roo.data.Store(...);
16154 var view = new Roo.View({
16156 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16158 singleSelect: true,
16159 selectedClass: "ydataview-selected",
16163 // listen for node click?
16164 view.on("click", function(vw, index, node, e){
16165 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16169 dataModel.load("foobar.xml");
16171 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16173 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16174 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16176 * Note: old style constructor is still suported (container, template, config)
16179 * Create a new View
16180 * @param {Object} config The config object
16183 Roo.View = function(config, depreciated_tpl, depreciated_config){
16185 this.parent = false;
16187 if (typeof(depreciated_tpl) == 'undefined') {
16188 // new way.. - universal constructor.
16189 Roo.apply(this, config);
16190 this.el = Roo.get(this.el);
16193 this.el = Roo.get(config);
16194 this.tpl = depreciated_tpl;
16195 Roo.apply(this, depreciated_config);
16197 this.wrapEl = this.el.wrap().wrap();
16198 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16201 if(typeof(this.tpl) == "string"){
16202 this.tpl = new Roo.Template(this.tpl);
16204 // support xtype ctors..
16205 this.tpl = new Roo.factory(this.tpl, Roo);
16209 this.tpl.compile();
16214 * @event beforeclick
16215 * Fires before a click is processed. Returns false to cancel the default action.
16216 * @param {Roo.View} this
16217 * @param {Number} index The index of the target node
16218 * @param {HTMLElement} node The target node
16219 * @param {Roo.EventObject} e The raw event object
16221 "beforeclick" : true,
16224 * Fires when a template node is clicked.
16225 * @param {Roo.View} this
16226 * @param {Number} index The index of the target node
16227 * @param {HTMLElement} node The target node
16228 * @param {Roo.EventObject} e The raw event object
16233 * Fires when a template node is double clicked.
16234 * @param {Roo.View} this
16235 * @param {Number} index The index of the target node
16236 * @param {HTMLElement} node The target node
16237 * @param {Roo.EventObject} e The raw event object
16241 * @event contextmenu
16242 * Fires when a template node is right clicked.
16243 * @param {Roo.View} this
16244 * @param {Number} index The index of the target node
16245 * @param {HTMLElement} node The target node
16246 * @param {Roo.EventObject} e The raw event object
16248 "contextmenu" : true,
16250 * @event selectionchange
16251 * Fires when the selected nodes change.
16252 * @param {Roo.View} this
16253 * @param {Array} selections Array of the selected nodes
16255 "selectionchange" : true,
16258 * @event beforeselect
16259 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16260 * @param {Roo.View} this
16261 * @param {HTMLElement} node The node to be selected
16262 * @param {Array} selections Array of currently selected nodes
16264 "beforeselect" : true,
16266 * @event preparedata
16267 * Fires on every row to render, to allow you to change the data.
16268 * @param {Roo.View} this
16269 * @param {Object} data to be rendered (change this)
16271 "preparedata" : true
16279 "click": this.onClick,
16280 "dblclick": this.onDblClick,
16281 "contextmenu": this.onContextMenu,
16285 this.selections = [];
16287 this.cmp = new Roo.CompositeElementLite([]);
16289 this.store = Roo.factory(this.store, Roo.data);
16290 this.setStore(this.store, true);
16293 if ( this.footer && this.footer.xtype) {
16295 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16297 this.footer.dataSource = this.store;
16298 this.footer.container = fctr;
16299 this.footer = Roo.factory(this.footer, Roo);
16300 fctr.insertFirst(this.el);
16302 // this is a bit insane - as the paging toolbar seems to detach the el..
16303 // dom.parentNode.parentNode.parentNode
16304 // they get detached?
16308 Roo.View.superclass.constructor.call(this);
16313 Roo.extend(Roo.View, Roo.util.Observable, {
16316 * @cfg {Roo.data.Store} store Data store to load data from.
16321 * @cfg {String|Roo.Element} el The container element.
16326 * @cfg {String|Roo.Template} tpl The template used by this View
16330 * @cfg {String} dataName the named area of the template to use as the data area
16331 * Works with domtemplates roo-name="name"
16335 * @cfg {String} selectedClass The css class to add to selected nodes
16337 selectedClass : "x-view-selected",
16339 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16344 * @cfg {String} text to display on mask (default Loading)
16348 * @cfg {Boolean} multiSelect Allow multiple selection
16350 multiSelect : false,
16352 * @cfg {Boolean} singleSelect Allow single selection
16354 singleSelect: false,
16357 * @cfg {Boolean} toggleSelect - selecting
16359 toggleSelect : false,
16362 * @cfg {Boolean} tickable - selecting
16367 * Returns the element this view is bound to.
16368 * @return {Roo.Element}
16370 getEl : function(){
16371 return this.wrapEl;
16377 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16379 refresh : function(){
16380 //Roo.log('refresh');
16383 // if we are using something like 'domtemplate', then
16384 // the what gets used is:
16385 // t.applySubtemplate(NAME, data, wrapping data..)
16386 // the outer template then get' applied with
16387 // the store 'extra data'
16388 // and the body get's added to the
16389 // roo-name="data" node?
16390 // <span class='roo-tpl-{name}'></span> ?????
16394 this.clearSelections();
16395 this.el.update("");
16397 var records = this.store.getRange();
16398 if(records.length < 1) {
16400 // is this valid?? = should it render a template??
16402 this.el.update(this.emptyText);
16406 if (this.dataName) {
16407 this.el.update(t.apply(this.store.meta)); //????
16408 el = this.el.child('.roo-tpl-' + this.dataName);
16411 for(var i = 0, len = records.length; i < len; i++){
16412 var data = this.prepareData(records[i].data, i, records[i]);
16413 this.fireEvent("preparedata", this, data, i, records[i]);
16415 var d = Roo.apply({}, data);
16418 Roo.apply(d, {'roo-id' : Roo.id()});
16422 Roo.each(this.parent.item, function(item){
16423 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16426 Roo.apply(d, {'roo-data-checked' : 'checked'});
16430 html[html.length] = Roo.util.Format.trim(
16432 t.applySubtemplate(this.dataName, d, this.store.meta) :
16439 el.update(html.join(""));
16440 this.nodes = el.dom.childNodes;
16441 this.updateIndexes(0);
16446 * Function to override to reformat the data that is sent to
16447 * the template for each node.
16448 * DEPRICATED - use the preparedata event handler.
16449 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16450 * a JSON object for an UpdateManager bound view).
16452 prepareData : function(data, index, record)
16454 this.fireEvent("preparedata", this, data, index, record);
16458 onUpdate : function(ds, record){
16459 // Roo.log('on update');
16460 this.clearSelections();
16461 var index = this.store.indexOf(record);
16462 var n = this.nodes[index];
16463 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16464 n.parentNode.removeChild(n);
16465 this.updateIndexes(index, index);
16471 onAdd : function(ds, records, index)
16473 //Roo.log(['on Add', ds, records, index] );
16474 this.clearSelections();
16475 if(this.nodes.length == 0){
16479 var n = this.nodes[index];
16480 for(var i = 0, len = records.length; i < len; i++){
16481 var d = this.prepareData(records[i].data, i, records[i]);
16483 this.tpl.insertBefore(n, d);
16486 this.tpl.append(this.el, d);
16489 this.updateIndexes(index);
16492 onRemove : function(ds, record, index){
16493 // Roo.log('onRemove');
16494 this.clearSelections();
16495 var el = this.dataName ?
16496 this.el.child('.roo-tpl-' + this.dataName) :
16499 el.dom.removeChild(this.nodes[index]);
16500 this.updateIndexes(index);
16504 * Refresh an individual node.
16505 * @param {Number} index
16507 refreshNode : function(index){
16508 this.onUpdate(this.store, this.store.getAt(index));
16511 updateIndexes : function(startIndex, endIndex){
16512 var ns = this.nodes;
16513 startIndex = startIndex || 0;
16514 endIndex = endIndex || ns.length - 1;
16515 for(var i = startIndex; i <= endIndex; i++){
16516 ns[i].nodeIndex = i;
16521 * Changes the data store this view uses and refresh the view.
16522 * @param {Store} store
16524 setStore : function(store, initial){
16525 if(!initial && this.store){
16526 this.store.un("datachanged", this.refresh);
16527 this.store.un("add", this.onAdd);
16528 this.store.un("remove", this.onRemove);
16529 this.store.un("update", this.onUpdate);
16530 this.store.un("clear", this.refresh);
16531 this.store.un("beforeload", this.onBeforeLoad);
16532 this.store.un("load", this.onLoad);
16533 this.store.un("loadexception", this.onLoad);
16537 store.on("datachanged", this.refresh, this);
16538 store.on("add", this.onAdd, this);
16539 store.on("remove", this.onRemove, this);
16540 store.on("update", this.onUpdate, this);
16541 store.on("clear", this.refresh, this);
16542 store.on("beforeload", this.onBeforeLoad, this);
16543 store.on("load", this.onLoad, this);
16544 store.on("loadexception", this.onLoad, this);
16552 * onbeforeLoad - masks the loading area.
16555 onBeforeLoad : function(store,opts)
16557 //Roo.log('onBeforeLoad');
16559 this.el.update("");
16561 this.el.mask(this.mask ? this.mask : "Loading" );
16563 onLoad : function ()
16570 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16571 * @param {HTMLElement} node
16572 * @return {HTMLElement} The template node
16574 findItemFromChild : function(node){
16575 var el = this.dataName ?
16576 this.el.child('.roo-tpl-' + this.dataName,true) :
16579 if(!node || node.parentNode == el){
16582 var p = node.parentNode;
16583 while(p && p != el){
16584 if(p.parentNode == el){
16593 onClick : function(e){
16594 var item = this.findItemFromChild(e.getTarget());
16596 var index = this.indexOf(item);
16597 if(this.onItemClick(item, index, e) !== false){
16598 this.fireEvent("click", this, index, item, e);
16601 this.clearSelections();
16606 onContextMenu : function(e){
16607 var item = this.findItemFromChild(e.getTarget());
16609 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16614 onDblClick : function(e){
16615 var item = this.findItemFromChild(e.getTarget());
16617 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16621 onItemClick : function(item, index, e)
16623 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16626 if (this.toggleSelect) {
16627 var m = this.isSelected(item) ? 'unselect' : 'select';
16630 _t[m](item, true, false);
16633 if(this.multiSelect || this.singleSelect){
16634 if(this.multiSelect && e.shiftKey && this.lastSelection){
16635 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16637 this.select(item, this.multiSelect && e.ctrlKey);
16638 this.lastSelection = item;
16641 if(!this.tickable){
16642 e.preventDefault();
16650 * Get the number of selected nodes.
16653 getSelectionCount : function(){
16654 return this.selections.length;
16658 * Get the currently selected nodes.
16659 * @return {Array} An array of HTMLElements
16661 getSelectedNodes : function(){
16662 return this.selections;
16666 * Get the indexes of the selected nodes.
16669 getSelectedIndexes : function(){
16670 var indexes = [], s = this.selections;
16671 for(var i = 0, len = s.length; i < len; i++){
16672 indexes.push(s[i].nodeIndex);
16678 * Clear all selections
16679 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16681 clearSelections : function(suppressEvent){
16682 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16683 this.cmp.elements = this.selections;
16684 this.cmp.removeClass(this.selectedClass);
16685 this.selections = [];
16686 if(!suppressEvent){
16687 this.fireEvent("selectionchange", this, this.selections);
16693 * Returns true if the passed node is selected
16694 * @param {HTMLElement/Number} node The node or node index
16695 * @return {Boolean}
16697 isSelected : function(node){
16698 var s = this.selections;
16702 node = this.getNode(node);
16703 return s.indexOf(node) !== -1;
16708 * @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
16709 * @param {Boolean} keepExisting (optional) true to keep existing selections
16710 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16712 select : function(nodeInfo, keepExisting, suppressEvent){
16713 if(nodeInfo instanceof Array){
16715 this.clearSelections(true);
16717 for(var i = 0, len = nodeInfo.length; i < len; i++){
16718 this.select(nodeInfo[i], true, true);
16722 var node = this.getNode(nodeInfo);
16723 if(!node || this.isSelected(node)){
16724 return; // already selected.
16727 this.clearSelections(true);
16730 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16731 Roo.fly(node).addClass(this.selectedClass);
16732 this.selections.push(node);
16733 if(!suppressEvent){
16734 this.fireEvent("selectionchange", this, this.selections);
16742 * @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
16743 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16744 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16746 unselect : function(nodeInfo, keepExisting, suppressEvent)
16748 if(nodeInfo instanceof Array){
16749 Roo.each(this.selections, function(s) {
16750 this.unselect(s, nodeInfo);
16754 var node = this.getNode(nodeInfo);
16755 if(!node || !this.isSelected(node)){
16756 //Roo.log("not selected");
16757 return; // not selected.
16761 Roo.each(this.selections, function(s) {
16763 Roo.fly(node).removeClass(this.selectedClass);
16770 this.selections= ns;
16771 this.fireEvent("selectionchange", this, this.selections);
16775 * Gets a template node.
16776 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16777 * @return {HTMLElement} The node or null if it wasn't found
16779 getNode : function(nodeInfo){
16780 if(typeof nodeInfo == "string"){
16781 return document.getElementById(nodeInfo);
16782 }else if(typeof nodeInfo == "number"){
16783 return this.nodes[nodeInfo];
16789 * Gets a range template nodes.
16790 * @param {Number} startIndex
16791 * @param {Number} endIndex
16792 * @return {Array} An array of nodes
16794 getNodes : function(start, end){
16795 var ns = this.nodes;
16796 start = start || 0;
16797 end = typeof end == "undefined" ? ns.length - 1 : end;
16800 for(var i = start; i <= end; i++){
16804 for(var i = start; i >= end; i--){
16812 * Finds the index of the passed node
16813 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16814 * @return {Number} The index of the node or -1
16816 indexOf : function(node){
16817 node = this.getNode(node);
16818 if(typeof node.nodeIndex == "number"){
16819 return node.nodeIndex;
16821 var ns = this.nodes;
16822 for(var i = 0, len = ns.length; i < len; i++){
16833 * based on jquery fullcalendar
16837 Roo.bootstrap = Roo.bootstrap || {};
16839 * @class Roo.bootstrap.Calendar
16840 * @extends Roo.bootstrap.Component
16841 * Bootstrap Calendar class
16842 * @cfg {Boolean} loadMask (true|false) default false
16843 * @cfg {Object} header generate the user specific header of the calendar, default false
16846 * Create a new Container
16847 * @param {Object} config The config object
16852 Roo.bootstrap.Calendar = function(config){
16853 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16857 * Fires when a date is selected
16858 * @param {DatePicker} this
16859 * @param {Date} date The selected date
16863 * @event monthchange
16864 * Fires when the displayed month changes
16865 * @param {DatePicker} this
16866 * @param {Date} date The selected month
16868 'monthchange': true,
16870 * @event evententer
16871 * Fires when mouse over an event
16872 * @param {Calendar} this
16873 * @param {event} Event
16875 'evententer': true,
16877 * @event eventleave
16878 * Fires when the mouse leaves an
16879 * @param {Calendar} this
16882 'eventleave': true,
16884 * @event eventclick
16885 * Fires when the mouse click an
16886 * @param {Calendar} this
16895 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16898 * @cfg {Number} startDay
16899 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16907 getAutoCreate : function(){
16910 var fc_button = function(name, corner, style, content ) {
16911 return Roo.apply({},{
16913 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16915 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16918 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16929 style : 'width:100%',
16936 cls : 'fc-header-left',
16938 fc_button('prev', 'left', 'arrow', '‹' ),
16939 fc_button('next', 'right', 'arrow', '›' ),
16940 { tag: 'span', cls: 'fc-header-space' },
16941 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16949 cls : 'fc-header-center',
16953 cls: 'fc-header-title',
16956 html : 'month / year'
16964 cls : 'fc-header-right',
16966 /* fc_button('month', 'left', '', 'month' ),
16967 fc_button('week', '', '', 'week' ),
16968 fc_button('day', 'right', '', 'day' )
16980 header = this.header;
16983 var cal_heads = function() {
16985 // fixme - handle this.
16987 for (var i =0; i < Date.dayNames.length; i++) {
16988 var d = Date.dayNames[i];
16991 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16992 html : d.substring(0,3)
16996 ret[0].cls += ' fc-first';
16997 ret[6].cls += ' fc-last';
17000 var cal_cell = function(n) {
17003 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17008 cls: 'fc-day-number',
17012 cls: 'fc-day-content',
17016 style: 'position: relative;' // height: 17px;
17028 var cal_rows = function() {
17031 for (var r = 0; r < 6; r++) {
17038 for (var i =0; i < Date.dayNames.length; i++) {
17039 var d = Date.dayNames[i];
17040 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17043 row.cn[0].cls+=' fc-first';
17044 row.cn[0].cn[0].style = 'min-height:90px';
17045 row.cn[6].cls+=' fc-last';
17049 ret[0].cls += ' fc-first';
17050 ret[4].cls += ' fc-prev-last';
17051 ret[5].cls += ' fc-last';
17058 cls: 'fc-border-separate',
17059 style : 'width:100%',
17067 cls : 'fc-first fc-last',
17085 cls : 'fc-content',
17086 style : "position: relative;",
17089 cls : 'fc-view fc-view-month fc-grid',
17090 style : 'position: relative',
17091 unselectable : 'on',
17094 cls : 'fc-event-container',
17095 style : 'position:absolute;z-index:8;top:0;left:0;'
17113 initEvents : function()
17116 throw "can not find store for calendar";
17122 style: "text-align:center",
17126 style: "background-color:white;width:50%;margin:250 auto",
17130 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17141 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17143 var size = this.el.select('.fc-content', true).first().getSize();
17144 this.maskEl.setSize(size.width, size.height);
17145 this.maskEl.enableDisplayMode("block");
17146 if(!this.loadMask){
17147 this.maskEl.hide();
17150 this.store = Roo.factory(this.store, Roo.data);
17151 this.store.on('load', this.onLoad, this);
17152 this.store.on('beforeload', this.onBeforeLoad, this);
17156 this.cells = this.el.select('.fc-day',true);
17157 //Roo.log(this.cells);
17158 this.textNodes = this.el.query('.fc-day-number');
17159 this.cells.addClassOnOver('fc-state-hover');
17161 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17162 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17163 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17164 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17166 this.on('monthchange', this.onMonthChange, this);
17168 this.update(new Date().clearTime());
17171 resize : function() {
17172 var sz = this.el.getSize();
17174 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17175 this.el.select('.fc-day-content div',true).setHeight(34);
17180 showPrevMonth : function(e){
17181 this.update(this.activeDate.add("mo", -1));
17183 showToday : function(e){
17184 this.update(new Date().clearTime());
17187 showNextMonth : function(e){
17188 this.update(this.activeDate.add("mo", 1));
17192 showPrevYear : function(){
17193 this.update(this.activeDate.add("y", -1));
17197 showNextYear : function(){
17198 this.update(this.activeDate.add("y", 1));
17203 update : function(date)
17205 var vd = this.activeDate;
17206 this.activeDate = date;
17207 // if(vd && this.el){
17208 // var t = date.getTime();
17209 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17210 // Roo.log('using add remove');
17212 // this.fireEvent('monthchange', this, date);
17214 // this.cells.removeClass("fc-state-highlight");
17215 // this.cells.each(function(c){
17216 // if(c.dateValue == t){
17217 // c.addClass("fc-state-highlight");
17218 // setTimeout(function(){
17219 // try{c.dom.firstChild.focus();}catch(e){}
17229 var days = date.getDaysInMonth();
17231 var firstOfMonth = date.getFirstDateOfMonth();
17232 var startingPos = firstOfMonth.getDay()-this.startDay;
17234 if(startingPos < this.startDay){
17238 var pm = date.add(Date.MONTH, -1);
17239 var prevStart = pm.getDaysInMonth()-startingPos;
17241 this.cells = this.el.select('.fc-day',true);
17242 this.textNodes = this.el.query('.fc-day-number');
17243 this.cells.addClassOnOver('fc-state-hover');
17245 var cells = this.cells.elements;
17246 var textEls = this.textNodes;
17248 Roo.each(cells, function(cell){
17249 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17252 days += startingPos;
17254 // convert everything to numbers so it's fast
17255 var day = 86400000;
17256 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17259 //Roo.log(prevStart);
17261 var today = new Date().clearTime().getTime();
17262 var sel = date.clearTime().getTime();
17263 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17264 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17265 var ddMatch = this.disabledDatesRE;
17266 var ddText = this.disabledDatesText;
17267 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17268 var ddaysText = this.disabledDaysText;
17269 var format = this.format;
17271 var setCellClass = function(cal, cell){
17275 //Roo.log('set Cell Class');
17277 var t = d.getTime();
17281 cell.dateValue = t;
17283 cell.className += " fc-today";
17284 cell.className += " fc-state-highlight";
17285 cell.title = cal.todayText;
17288 // disable highlight in other month..
17289 //cell.className += " fc-state-highlight";
17294 cell.className = " fc-state-disabled";
17295 cell.title = cal.minText;
17299 cell.className = " fc-state-disabled";
17300 cell.title = cal.maxText;
17304 if(ddays.indexOf(d.getDay()) != -1){
17305 cell.title = ddaysText;
17306 cell.className = " fc-state-disabled";
17309 if(ddMatch && format){
17310 var fvalue = d.dateFormat(format);
17311 if(ddMatch.test(fvalue)){
17312 cell.title = ddText.replace("%0", fvalue);
17313 cell.className = " fc-state-disabled";
17317 if (!cell.initialClassName) {
17318 cell.initialClassName = cell.dom.className;
17321 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17326 for(; i < startingPos; i++) {
17327 textEls[i].innerHTML = (++prevStart);
17328 d.setDate(d.getDate()+1);
17330 cells[i].className = "fc-past fc-other-month";
17331 setCellClass(this, cells[i]);
17336 for(; i < days; i++){
17337 intDay = i - startingPos + 1;
17338 textEls[i].innerHTML = (intDay);
17339 d.setDate(d.getDate()+1);
17341 cells[i].className = ''; // "x-date-active";
17342 setCellClass(this, cells[i]);
17346 for(; i < 42; i++) {
17347 textEls[i].innerHTML = (++extraDays);
17348 d.setDate(d.getDate()+1);
17350 cells[i].className = "fc-future fc-other-month";
17351 setCellClass(this, cells[i]);
17354 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17356 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17358 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17359 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17361 if(totalRows != 6){
17362 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17363 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17366 this.fireEvent('monthchange', this, date);
17370 if(!this.internalRender){
17371 var main = this.el.dom.firstChild;
17372 var w = main.offsetWidth;
17373 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17374 Roo.fly(main).setWidth(w);
17375 this.internalRender = true;
17376 // opera does not respect the auto grow header center column
17377 // then, after it gets a width opera refuses to recalculate
17378 // without a second pass
17379 if(Roo.isOpera && !this.secondPass){
17380 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17381 this.secondPass = true;
17382 this.update.defer(10, this, [date]);
17389 findCell : function(dt) {
17390 dt = dt.clearTime().getTime();
17392 this.cells.each(function(c){
17393 //Roo.log("check " +c.dateValue + '?=' + dt);
17394 if(c.dateValue == dt){
17404 findCells : function(ev) {
17405 var s = ev.start.clone().clearTime().getTime();
17407 var e= ev.end.clone().clearTime().getTime();
17410 this.cells.each(function(c){
17411 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17413 if(c.dateValue > e){
17416 if(c.dateValue < s){
17425 // findBestRow: function(cells)
17429 // for (var i =0 ; i < cells.length;i++) {
17430 // ret = Math.max(cells[i].rows || 0,ret);
17437 addItem : function(ev)
17439 // look for vertical location slot in
17440 var cells = this.findCells(ev);
17442 // ev.row = this.findBestRow(cells);
17444 // work out the location.
17448 for(var i =0; i < cells.length; i++) {
17450 cells[i].row = cells[0].row;
17453 cells[i].row = cells[i].row + 1;
17463 if (crow.start.getY() == cells[i].getY()) {
17465 crow.end = cells[i];
17482 cells[0].events.push(ev);
17484 this.calevents.push(ev);
17487 clearEvents: function() {
17489 if(!this.calevents){
17493 Roo.each(this.cells.elements, function(c){
17499 Roo.each(this.calevents, function(e) {
17500 Roo.each(e.els, function(el) {
17501 el.un('mouseenter' ,this.onEventEnter, this);
17502 el.un('mouseleave' ,this.onEventLeave, this);
17507 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17513 renderEvents: function()
17517 this.cells.each(function(c) {
17526 if(c.row != c.events.length){
17527 r = 4 - (4 - (c.row - c.events.length));
17530 c.events = ev.slice(0, r);
17531 c.more = ev.slice(r);
17533 if(c.more.length && c.more.length == 1){
17534 c.events.push(c.more.pop());
17537 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17541 this.cells.each(function(c) {
17543 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17546 for (var e = 0; e < c.events.length; e++){
17547 var ev = c.events[e];
17548 var rows = ev.rows;
17550 for(var i = 0; i < rows.length; i++) {
17552 // how many rows should it span..
17555 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17556 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17558 unselectable : "on",
17561 cls: 'fc-event-inner',
17565 // cls: 'fc-event-time',
17566 // html : cells.length > 1 ? '' : ev.time
17570 cls: 'fc-event-title',
17571 html : String.format('{0}', ev.title)
17578 cls: 'ui-resizable-handle ui-resizable-e',
17579 html : '  '
17586 cfg.cls += ' fc-event-start';
17588 if ((i+1) == rows.length) {
17589 cfg.cls += ' fc-event-end';
17592 var ctr = _this.el.select('.fc-event-container',true).first();
17593 var cg = ctr.createChild(cfg);
17595 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17596 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17598 var r = (c.more.length) ? 1 : 0;
17599 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17600 cg.setWidth(ebox.right - sbox.x -2);
17602 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17603 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17604 cg.on('click', _this.onEventClick, _this, ev);
17615 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17616 style : 'position: absolute',
17617 unselectable : "on",
17620 cls: 'fc-event-inner',
17624 cls: 'fc-event-title',
17632 cls: 'ui-resizable-handle ui-resizable-e',
17633 html : '  '
17639 var ctr = _this.el.select('.fc-event-container',true).first();
17640 var cg = ctr.createChild(cfg);
17642 var sbox = c.select('.fc-day-content',true).first().getBox();
17643 var ebox = c.select('.fc-day-content',true).first().getBox();
17645 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17646 cg.setWidth(ebox.right - sbox.x -2);
17648 cg.on('click', _this.onMoreEventClick, _this, c.more);
17658 onEventEnter: function (e, el,event,d) {
17659 this.fireEvent('evententer', this, el, event);
17662 onEventLeave: function (e, el,event,d) {
17663 this.fireEvent('eventleave', this, el, event);
17666 onEventClick: function (e, el,event,d) {
17667 this.fireEvent('eventclick', this, el, event);
17670 onMonthChange: function () {
17674 onMoreEventClick: function(e, el, more)
17678 this.calpopover.placement = 'right';
17679 this.calpopover.setTitle('More');
17681 this.calpopover.setContent('');
17683 var ctr = this.calpopover.el.select('.popover-content', true).first();
17685 Roo.each(more, function(m){
17687 cls : 'fc-event-hori fc-event-draggable',
17690 var cg = ctr.createChild(cfg);
17692 cg.on('click', _this.onEventClick, _this, m);
17695 this.calpopover.show(el);
17700 onLoad: function ()
17702 this.calevents = [];
17705 if(this.store.getCount() > 0){
17706 this.store.data.each(function(d){
17709 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17710 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17711 time : d.data.start_time,
17712 title : d.data.title,
17713 description : d.data.description,
17714 venue : d.data.venue
17719 this.renderEvents();
17721 if(this.calevents.length && this.loadMask){
17722 this.maskEl.hide();
17726 onBeforeLoad: function()
17728 this.clearEvents();
17730 this.maskEl.show();
17744 * @class Roo.bootstrap.Popover
17745 * @extends Roo.bootstrap.Component
17746 * Bootstrap Popover class
17747 * @cfg {String} html contents of the popover (or false to use children..)
17748 * @cfg {String} title of popover (or false to hide)
17749 * @cfg {String} placement how it is placed
17750 * @cfg {String} trigger click || hover (or false to trigger manually)
17751 * @cfg {String} over what (parent or false to trigger manually.)
17752 * @cfg {Number} delay - delay before showing
17755 * Create a new Popover
17756 * @param {Object} config The config object
17759 Roo.bootstrap.Popover = function(config){
17760 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17766 * After the popover show
17768 * @param {Roo.bootstrap.Popover} this
17773 * After the popover hide
17775 * @param {Roo.bootstrap.Popover} this
17781 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17783 title: 'Fill in a title',
17786 placement : 'right',
17787 trigger : 'hover', // hover
17793 can_build_overlaid : false,
17795 getChildContainer : function()
17797 return this.el.select('.popover-content',true).first();
17800 getAutoCreate : function(){
17803 cls : 'popover roo-dynamic',
17804 style: 'display:block',
17810 cls : 'popover-inner',
17814 cls: 'popover-title popover-header',
17818 cls : 'popover-content popover-body',
17829 setTitle: function(str)
17832 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17834 setContent: function(str)
17837 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17839 // as it get's added to the bottom of the page.
17840 onRender : function(ct, position)
17842 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17844 var cfg = Roo.apply({}, this.getAutoCreate());
17848 cfg.cls += ' ' + this.cls;
17851 cfg.style = this.style;
17853 //Roo.log("adding to ");
17854 this.el = Roo.get(document.body).createChild(cfg, position);
17855 // Roo.log(this.el);
17860 initEvents : function()
17862 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17863 this.el.enableDisplayMode('block');
17865 if (this.over === false) {
17868 if (this.triggers === false) {
17871 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17872 var triggers = this.trigger ? this.trigger.split(' ') : [];
17873 Roo.each(triggers, function(trigger) {
17875 if (trigger == 'click') {
17876 on_el.on('click', this.toggle, this);
17877 } else if (trigger != 'manual') {
17878 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17879 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17881 on_el.on(eventIn ,this.enter, this);
17882 on_el.on(eventOut, this.leave, this);
17893 toggle : function () {
17894 this.hoverState == 'in' ? this.leave() : this.enter();
17897 enter : function () {
17899 clearTimeout(this.timeout);
17901 this.hoverState = 'in';
17903 if (!this.delay || !this.delay.show) {
17908 this.timeout = setTimeout(function () {
17909 if (_t.hoverState == 'in') {
17912 }, this.delay.show)
17915 leave : function() {
17916 clearTimeout(this.timeout);
17918 this.hoverState = 'out';
17920 if (!this.delay || !this.delay.hide) {
17925 this.timeout = setTimeout(function () {
17926 if (_t.hoverState == 'out') {
17929 }, this.delay.hide)
17932 show : function (on_el)
17935 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17939 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17940 if (this.html !== false) {
17941 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17943 this.el.removeClass([
17944 'fade','top','bottom', 'left', 'right','in',
17945 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17947 if (!this.title.length) {
17948 this.el.select('.popover-title',true).hide();
17951 var placement = typeof this.placement == 'function' ?
17952 this.placement.call(this, this.el, on_el) :
17955 var autoToken = /\s?auto?\s?/i;
17956 var autoPlace = autoToken.test(placement);
17958 placement = placement.replace(autoToken, '') || 'top';
17962 //this.el.setXY([0,0]);
17964 this.el.dom.style.display='block';
17965 this.el.addClass(placement);
17967 //this.el.appendTo(on_el);
17969 var p = this.getPosition();
17970 var box = this.el.getBox();
17975 var align = Roo.bootstrap.Popover.alignment[placement];
17978 this.el.alignTo(on_el, align[0],align[1]);
17979 //var arrow = this.el.select('.arrow',true).first();
17980 //arrow.set(align[2],
17982 this.el.addClass('in');
17985 if (this.el.hasClass('fade')) {
17989 this.hoverState = 'in';
17991 this.fireEvent('show', this);
17996 this.el.setXY([0,0]);
17997 this.el.removeClass('in');
17999 this.hoverState = null;
18001 this.fireEvent('hide', this);
18006 Roo.bootstrap.Popover.alignment = {
18007 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18008 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18009 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18010 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18021 * @class Roo.bootstrap.Progress
18022 * @extends Roo.bootstrap.Component
18023 * Bootstrap Progress class
18024 * @cfg {Boolean} striped striped of the progress bar
18025 * @cfg {Boolean} active animated of the progress bar
18029 * Create a new Progress
18030 * @param {Object} config The config object
18033 Roo.bootstrap.Progress = function(config){
18034 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18037 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18042 getAutoCreate : function(){
18050 cfg.cls += ' progress-striped';
18054 cfg.cls += ' active';
18073 * @class Roo.bootstrap.ProgressBar
18074 * @extends Roo.bootstrap.Component
18075 * Bootstrap ProgressBar class
18076 * @cfg {Number} aria_valuenow aria-value now
18077 * @cfg {Number} aria_valuemin aria-value min
18078 * @cfg {Number} aria_valuemax aria-value max
18079 * @cfg {String} label label for the progress bar
18080 * @cfg {String} panel (success | info | warning | danger )
18081 * @cfg {String} role role of the progress bar
18082 * @cfg {String} sr_only text
18086 * Create a new ProgressBar
18087 * @param {Object} config The config object
18090 Roo.bootstrap.ProgressBar = function(config){
18091 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18094 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18098 aria_valuemax : 100,
18104 getAutoCreate : function()
18109 cls: 'progress-bar',
18110 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18122 cfg.role = this.role;
18125 if(this.aria_valuenow){
18126 cfg['aria-valuenow'] = this.aria_valuenow;
18129 if(this.aria_valuemin){
18130 cfg['aria-valuemin'] = this.aria_valuemin;
18133 if(this.aria_valuemax){
18134 cfg['aria-valuemax'] = this.aria_valuemax;
18137 if(this.label && !this.sr_only){
18138 cfg.html = this.label;
18142 cfg.cls += ' progress-bar-' + this.panel;
18148 update : function(aria_valuenow)
18150 this.aria_valuenow = aria_valuenow;
18152 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18167 * @class Roo.bootstrap.TabGroup
18168 * @extends Roo.bootstrap.Column
18169 * Bootstrap Column class
18170 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18171 * @cfg {Boolean} carousel true to make the group behave like a carousel
18172 * @cfg {Boolean} bullets show bullets for the panels
18173 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18174 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18175 * @cfg {Boolean} showarrow (true|false) show arrow default true
18178 * Create a new TabGroup
18179 * @param {Object} config The config object
18182 Roo.bootstrap.TabGroup = function(config){
18183 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18185 this.navId = Roo.id();
18188 Roo.bootstrap.TabGroup.register(this);
18192 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18195 transition : false,
18200 slideOnTouch : false,
18203 getAutoCreate : function()
18205 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18207 cfg.cls += ' tab-content';
18209 if (this.carousel) {
18210 cfg.cls += ' carousel slide';
18213 cls : 'carousel-inner',
18217 if(this.bullets && !Roo.isTouch){
18220 cls : 'carousel-bullets',
18224 if(this.bullets_cls){
18225 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18232 cfg.cn[0].cn.push(bullets);
18235 if(this.showarrow){
18236 cfg.cn[0].cn.push({
18238 class : 'carousel-arrow',
18242 class : 'carousel-prev',
18246 class : 'fa fa-chevron-left'
18252 class : 'carousel-next',
18256 class : 'fa fa-chevron-right'
18269 initEvents: function()
18271 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18272 // this.el.on("touchstart", this.onTouchStart, this);
18275 if(this.autoslide){
18278 this.slideFn = window.setInterval(function() {
18279 _this.showPanelNext();
18283 if(this.showarrow){
18284 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18285 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18291 // onTouchStart : function(e, el, o)
18293 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18297 // this.showPanelNext();
18301 getChildContainer : function()
18303 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18307 * register a Navigation item
18308 * @param {Roo.bootstrap.NavItem} the navitem to add
18310 register : function(item)
18312 this.tabs.push( item);
18313 item.navId = this.navId; // not really needed..
18318 getActivePanel : function()
18321 Roo.each(this.tabs, function(t) {
18331 getPanelByName : function(n)
18334 Roo.each(this.tabs, function(t) {
18335 if (t.tabId == n) {
18343 indexOfPanel : function(p)
18346 Roo.each(this.tabs, function(t,i) {
18347 if (t.tabId == p.tabId) {
18356 * show a specific panel
18357 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18358 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18360 showPanel : function (pan)
18362 if(this.transition || typeof(pan) == 'undefined'){
18363 Roo.log("waiting for the transitionend");
18367 if (typeof(pan) == 'number') {
18368 pan = this.tabs[pan];
18371 if (typeof(pan) == 'string') {
18372 pan = this.getPanelByName(pan);
18375 var cur = this.getActivePanel();
18378 Roo.log('pan or acitve pan is undefined');
18382 if (pan.tabId == this.getActivePanel().tabId) {
18386 if (false === cur.fireEvent('beforedeactivate')) {
18390 if(this.bullets > 0 && !Roo.isTouch){
18391 this.setActiveBullet(this.indexOfPanel(pan));
18394 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18396 //class="carousel-item carousel-item-next carousel-item-left"
18398 this.transition = true;
18399 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18400 var lr = dir == 'next' ? 'left' : 'right';
18401 pan.el.addClass(dir); // or prev
18402 pan.el.addClass('carousel-item-' + dir); // or prev
18403 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18404 cur.el.addClass(lr); // or right
18405 pan.el.addClass(lr);
18406 cur.el.addClass('carousel-item-' +lr); // or right
18407 pan.el.addClass('carousel-item-' +lr);
18411 cur.el.on('transitionend', function() {
18412 Roo.log("trans end?");
18414 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18415 pan.setActive(true);
18417 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18418 cur.setActive(false);
18420 _this.transition = false;
18422 }, this, { single: true } );
18427 cur.setActive(false);
18428 pan.setActive(true);
18433 showPanelNext : function()
18435 var i = this.indexOfPanel(this.getActivePanel());
18437 if (i >= this.tabs.length - 1 && !this.autoslide) {
18441 if (i >= this.tabs.length - 1 && this.autoslide) {
18445 this.showPanel(this.tabs[i+1]);
18448 showPanelPrev : function()
18450 var i = this.indexOfPanel(this.getActivePanel());
18452 if (i < 1 && !this.autoslide) {
18456 if (i < 1 && this.autoslide) {
18457 i = this.tabs.length;
18460 this.showPanel(this.tabs[i-1]);
18464 addBullet: function()
18466 if(!this.bullets || Roo.isTouch){
18469 var ctr = this.el.select('.carousel-bullets',true).first();
18470 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18471 var bullet = ctr.createChild({
18472 cls : 'bullet bullet-' + i
18473 },ctr.dom.lastChild);
18478 bullet.on('click', (function(e, el, o, ii, t){
18480 e.preventDefault();
18482 this.showPanel(ii);
18484 if(this.autoslide && this.slideFn){
18485 clearInterval(this.slideFn);
18486 this.slideFn = window.setInterval(function() {
18487 _this.showPanelNext();
18491 }).createDelegate(this, [i, bullet], true));
18496 setActiveBullet : function(i)
18502 Roo.each(this.el.select('.bullet', true).elements, function(el){
18503 el.removeClass('selected');
18506 var bullet = this.el.select('.bullet-' + i, true).first();
18512 bullet.addClass('selected');
18523 Roo.apply(Roo.bootstrap.TabGroup, {
18527 * register a Navigation Group
18528 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18530 register : function(navgrp)
18532 this.groups[navgrp.navId] = navgrp;
18536 * fetch a Navigation Group based on the navigation ID
18537 * if one does not exist , it will get created.
18538 * @param {string} the navgroup to add
18539 * @returns {Roo.bootstrap.NavGroup} the navgroup
18541 get: function(navId) {
18542 if (typeof(this.groups[navId]) == 'undefined') {
18543 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18545 return this.groups[navId] ;
18560 * @class Roo.bootstrap.TabPanel
18561 * @extends Roo.bootstrap.Component
18562 * Bootstrap TabPanel class
18563 * @cfg {Boolean} active panel active
18564 * @cfg {String} html panel content
18565 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18566 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18567 * @cfg {String} href click to link..
18571 * Create a new TabPanel
18572 * @param {Object} config The config object
18575 Roo.bootstrap.TabPanel = function(config){
18576 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18580 * Fires when the active status changes
18581 * @param {Roo.bootstrap.TabPanel} this
18582 * @param {Boolean} state the new state
18587 * @event beforedeactivate
18588 * Fires before a tab is de-activated - can be used to do validation on a form.
18589 * @param {Roo.bootstrap.TabPanel} this
18590 * @return {Boolean} false if there is an error
18593 'beforedeactivate': true
18596 this.tabId = this.tabId || Roo.id();
18600 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18608 getAutoCreate : function(){
18613 // item is needed for carousel - not sure if it has any effect otherwise
18614 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18615 html: this.html || ''
18619 cfg.cls += ' active';
18623 cfg.tabId = this.tabId;
18631 initEvents: function()
18633 var p = this.parent();
18635 this.navId = this.navId || p.navId;
18637 if (typeof(this.navId) != 'undefined') {
18638 // not really needed.. but just in case.. parent should be a NavGroup.
18639 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18643 var i = tg.tabs.length - 1;
18645 if(this.active && tg.bullets > 0 && i < tg.bullets){
18646 tg.setActiveBullet(i);
18650 this.el.on('click', this.onClick, this);
18653 this.el.on("touchstart", this.onTouchStart, this);
18654 this.el.on("touchmove", this.onTouchMove, this);
18655 this.el.on("touchend", this.onTouchEnd, this);
18660 onRender : function(ct, position)
18662 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18665 setActive : function(state)
18667 Roo.log("panel - set active " + this.tabId + "=" + state);
18669 this.active = state;
18671 this.el.removeClass('active');
18673 } else if (!this.el.hasClass('active')) {
18674 this.el.addClass('active');
18677 this.fireEvent('changed', this, state);
18680 onClick : function(e)
18682 e.preventDefault();
18684 if(!this.href.length){
18688 window.location.href = this.href;
18697 onTouchStart : function(e)
18699 this.swiping = false;
18701 this.startX = e.browserEvent.touches[0].clientX;
18702 this.startY = e.browserEvent.touches[0].clientY;
18705 onTouchMove : function(e)
18707 this.swiping = true;
18709 this.endX = e.browserEvent.touches[0].clientX;
18710 this.endY = e.browserEvent.touches[0].clientY;
18713 onTouchEnd : function(e)
18720 var tabGroup = this.parent();
18722 if(this.endX > this.startX){ // swiping right
18723 tabGroup.showPanelPrev();
18727 if(this.startX > this.endX){ // swiping left
18728 tabGroup.showPanelNext();
18747 * @class Roo.bootstrap.DateField
18748 * @extends Roo.bootstrap.Input
18749 * Bootstrap DateField class
18750 * @cfg {Number} weekStart default 0
18751 * @cfg {String} viewMode default empty, (months|years)
18752 * @cfg {String} minViewMode default empty, (months|years)
18753 * @cfg {Number} startDate default -Infinity
18754 * @cfg {Number} endDate default Infinity
18755 * @cfg {Boolean} todayHighlight default false
18756 * @cfg {Boolean} todayBtn default false
18757 * @cfg {Boolean} calendarWeeks default false
18758 * @cfg {Object} daysOfWeekDisabled default empty
18759 * @cfg {Boolean} singleMode default false (true | false)
18761 * @cfg {Boolean} keyboardNavigation default true
18762 * @cfg {String} language default en
18765 * Create a new DateField
18766 * @param {Object} config The config object
18769 Roo.bootstrap.DateField = function(config){
18770 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18774 * Fires when this field show.
18775 * @param {Roo.bootstrap.DateField} this
18776 * @param {Mixed} date The date value
18781 * Fires when this field hide.
18782 * @param {Roo.bootstrap.DateField} this
18783 * @param {Mixed} date The date value
18788 * Fires when select a date.
18789 * @param {Roo.bootstrap.DateField} this
18790 * @param {Mixed} date The date value
18794 * @event beforeselect
18795 * Fires when before select a date.
18796 * @param {Roo.bootstrap.DateField} this
18797 * @param {Mixed} date The date value
18799 beforeselect : true
18803 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18806 * @cfg {String} format
18807 * The default date format string which can be overriden for localization support. The format must be
18808 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18812 * @cfg {String} altFormats
18813 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18814 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18816 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18824 todayHighlight : false,
18830 keyboardNavigation: true,
18832 calendarWeeks: false,
18834 startDate: -Infinity,
18838 daysOfWeekDisabled: [],
18842 singleMode : false,
18844 UTCDate: function()
18846 return new Date(Date.UTC.apply(Date, arguments));
18849 UTCToday: function()
18851 var today = new Date();
18852 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18855 getDate: function() {
18856 var d = this.getUTCDate();
18857 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18860 getUTCDate: function() {
18864 setDate: function(d) {
18865 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18868 setUTCDate: function(d) {
18870 this.setValue(this.formatDate(this.date));
18873 onRender: function(ct, position)
18876 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18878 this.language = this.language || 'en';
18879 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18880 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18882 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18883 this.format = this.format || 'm/d/y';
18884 this.isInline = false;
18885 this.isInput = true;
18886 this.component = this.el.select('.add-on', true).first() || false;
18887 this.component = (this.component && this.component.length === 0) ? false : this.component;
18888 this.hasInput = this.component && this.inputEl().length;
18890 if (typeof(this.minViewMode === 'string')) {
18891 switch (this.minViewMode) {
18893 this.minViewMode = 1;
18896 this.minViewMode = 2;
18899 this.minViewMode = 0;
18904 if (typeof(this.viewMode === 'string')) {
18905 switch (this.viewMode) {
18918 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18920 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18922 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18924 this.picker().on('mousedown', this.onMousedown, this);
18925 this.picker().on('click', this.onClick, this);
18927 this.picker().addClass('datepicker-dropdown');
18929 this.startViewMode = this.viewMode;
18931 if(this.singleMode){
18932 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18933 v.setVisibilityMode(Roo.Element.DISPLAY);
18937 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18938 v.setStyle('width', '189px');
18942 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18943 if(!this.calendarWeeks){
18948 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18949 v.attr('colspan', function(i, val){
18950 return parseInt(val) + 1;
18955 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18957 this.setStartDate(this.startDate);
18958 this.setEndDate(this.endDate);
18960 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18967 if(this.isInline) {
18972 picker : function()
18974 return this.pickerEl;
18975 // return this.el.select('.datepicker', true).first();
18978 fillDow: function()
18980 var dowCnt = this.weekStart;
18989 if(this.calendarWeeks){
18997 while (dowCnt < this.weekStart + 7) {
19001 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19005 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19008 fillMonths: function()
19011 var months = this.picker().select('>.datepicker-months td', true).first();
19013 months.dom.innerHTML = '';
19019 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19022 months.createChild(month);
19029 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;
19031 if (this.date < this.startDate) {
19032 this.viewDate = new Date(this.startDate);
19033 } else if (this.date > this.endDate) {
19034 this.viewDate = new Date(this.endDate);
19036 this.viewDate = new Date(this.date);
19044 var d = new Date(this.viewDate),
19045 year = d.getUTCFullYear(),
19046 month = d.getUTCMonth(),
19047 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19048 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19049 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19050 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19051 currentDate = this.date && this.date.valueOf(),
19052 today = this.UTCToday();
19054 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19056 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19058 // this.picker.select('>tfoot th.today').
19059 // .text(dates[this.language].today)
19060 // .toggle(this.todayBtn !== false);
19062 this.updateNavArrows();
19065 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19067 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19069 prevMonth.setUTCDate(day);
19071 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19073 var nextMonth = new Date(prevMonth);
19075 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19077 nextMonth = nextMonth.valueOf();
19079 var fillMonths = false;
19081 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19083 while(prevMonth.valueOf() <= nextMonth) {
19086 if (prevMonth.getUTCDay() === this.weekStart) {
19088 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19096 if(this.calendarWeeks){
19097 // ISO 8601: First week contains first thursday.
19098 // ISO also states week starts on Monday, but we can be more abstract here.
19100 // Start of current week: based on weekstart/current date
19101 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19102 // Thursday of this week
19103 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19104 // First Thursday of year, year from thursday
19105 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19106 // Calendar week: ms between thursdays, div ms per day, div 7 days
19107 calWeek = (th - yth) / 864e5 / 7 + 1;
19109 fillMonths.cn.push({
19117 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19119 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19122 if (this.todayHighlight &&
19123 prevMonth.getUTCFullYear() == today.getFullYear() &&
19124 prevMonth.getUTCMonth() == today.getMonth() &&
19125 prevMonth.getUTCDate() == today.getDate()) {
19126 clsName += ' today';
19129 if (currentDate && prevMonth.valueOf() === currentDate) {
19130 clsName += ' active';
19133 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19134 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19135 clsName += ' disabled';
19138 fillMonths.cn.push({
19140 cls: 'day ' + clsName,
19141 html: prevMonth.getDate()
19144 prevMonth.setDate(prevMonth.getDate()+1);
19147 var currentYear = this.date && this.date.getUTCFullYear();
19148 var currentMonth = this.date && this.date.getUTCMonth();
19150 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19152 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19153 v.removeClass('active');
19155 if(currentYear === year && k === currentMonth){
19156 v.addClass('active');
19159 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19160 v.addClass('disabled');
19166 year = parseInt(year/10, 10) * 10;
19168 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19170 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19173 for (var i = -1; i < 11; i++) {
19174 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19176 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19184 showMode: function(dir)
19187 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19190 Roo.each(this.picker().select('>div',true).elements, function(v){
19191 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19194 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19199 if(this.isInline) {
19203 this.picker().removeClass(['bottom', 'top']);
19205 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19207 * place to the top of element!
19211 this.picker().addClass('top');
19212 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19217 this.picker().addClass('bottom');
19219 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19222 parseDate : function(value)
19224 if(!value || value instanceof Date){
19227 var v = Date.parseDate(value, this.format);
19228 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19229 v = Date.parseDate(value, 'Y-m-d');
19231 if(!v && this.altFormats){
19232 if(!this.altFormatsArray){
19233 this.altFormatsArray = this.altFormats.split("|");
19235 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19236 v = Date.parseDate(value, this.altFormatsArray[i]);
19242 formatDate : function(date, fmt)
19244 return (!date || !(date instanceof Date)) ?
19245 date : date.dateFormat(fmt || this.format);
19248 onFocus : function()
19250 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19254 onBlur : function()
19256 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19258 var d = this.inputEl().getValue();
19265 showPopup : function()
19267 this.picker().show();
19271 this.fireEvent('showpopup', this, this.date);
19274 hidePopup : function()
19276 if(this.isInline) {
19279 this.picker().hide();
19280 this.viewMode = this.startViewMode;
19283 this.fireEvent('hidepopup', this, this.date);
19287 onMousedown: function(e)
19289 e.stopPropagation();
19290 e.preventDefault();
19295 Roo.bootstrap.DateField.superclass.keyup.call(this);
19299 setValue: function(v)
19301 if(this.fireEvent('beforeselect', this, v) !== false){
19302 var d = new Date(this.parseDate(v) ).clearTime();
19304 if(isNaN(d.getTime())){
19305 this.date = this.viewDate = '';
19306 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19310 v = this.formatDate(d);
19312 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19314 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19318 this.fireEvent('select', this, this.date);
19322 getValue: function()
19324 return this.formatDate(this.date);
19327 fireKey: function(e)
19329 if (!this.picker().isVisible()){
19330 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19336 var dateChanged = false,
19338 newDate, newViewDate;
19343 e.preventDefault();
19347 if (!this.keyboardNavigation) {
19350 dir = e.keyCode == 37 ? -1 : 1;
19353 newDate = this.moveYear(this.date, dir);
19354 newViewDate = this.moveYear(this.viewDate, dir);
19355 } else if (e.shiftKey){
19356 newDate = this.moveMonth(this.date, dir);
19357 newViewDate = this.moveMonth(this.viewDate, dir);
19359 newDate = new Date(this.date);
19360 newDate.setUTCDate(this.date.getUTCDate() + dir);
19361 newViewDate = new Date(this.viewDate);
19362 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19364 if (this.dateWithinRange(newDate)){
19365 this.date = newDate;
19366 this.viewDate = newViewDate;
19367 this.setValue(this.formatDate(this.date));
19369 e.preventDefault();
19370 dateChanged = true;
19375 if (!this.keyboardNavigation) {
19378 dir = e.keyCode == 38 ? -1 : 1;
19380 newDate = this.moveYear(this.date, dir);
19381 newViewDate = this.moveYear(this.viewDate, dir);
19382 } else if (e.shiftKey){
19383 newDate = this.moveMonth(this.date, dir);
19384 newViewDate = this.moveMonth(this.viewDate, dir);
19386 newDate = new Date(this.date);
19387 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19388 newViewDate = new Date(this.viewDate);
19389 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19391 if (this.dateWithinRange(newDate)){
19392 this.date = newDate;
19393 this.viewDate = newViewDate;
19394 this.setValue(this.formatDate(this.date));
19396 e.preventDefault();
19397 dateChanged = true;
19401 this.setValue(this.formatDate(this.date));
19403 e.preventDefault();
19406 this.setValue(this.formatDate(this.date));
19420 onClick: function(e)
19422 e.stopPropagation();
19423 e.preventDefault();
19425 var target = e.getTarget();
19427 if(target.nodeName.toLowerCase() === 'i'){
19428 target = Roo.get(target).dom.parentNode;
19431 var nodeName = target.nodeName;
19432 var className = target.className;
19433 var html = target.innerHTML;
19434 //Roo.log(nodeName);
19436 switch(nodeName.toLowerCase()) {
19438 switch(className) {
19444 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19445 switch(this.viewMode){
19447 this.viewDate = this.moveMonth(this.viewDate, dir);
19451 this.viewDate = this.moveYear(this.viewDate, dir);
19457 var date = new Date();
19458 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19460 this.setValue(this.formatDate(this.date));
19467 if (className.indexOf('disabled') < 0) {
19468 this.viewDate.setUTCDate(1);
19469 if (className.indexOf('month') > -1) {
19470 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19472 var year = parseInt(html, 10) || 0;
19473 this.viewDate.setUTCFullYear(year);
19477 if(this.singleMode){
19478 this.setValue(this.formatDate(this.viewDate));
19489 //Roo.log(className);
19490 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19491 var day = parseInt(html, 10) || 1;
19492 var year = this.viewDate.getUTCFullYear(),
19493 month = this.viewDate.getUTCMonth();
19495 if (className.indexOf('old') > -1) {
19502 } else if (className.indexOf('new') > -1) {
19510 //Roo.log([year,month,day]);
19511 this.date = this.UTCDate(year, month, day,0,0,0,0);
19512 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19514 //Roo.log(this.formatDate(this.date));
19515 this.setValue(this.formatDate(this.date));
19522 setStartDate: function(startDate)
19524 this.startDate = startDate || -Infinity;
19525 if (this.startDate !== -Infinity) {
19526 this.startDate = this.parseDate(this.startDate);
19529 this.updateNavArrows();
19532 setEndDate: function(endDate)
19534 this.endDate = endDate || Infinity;
19535 if (this.endDate !== Infinity) {
19536 this.endDate = this.parseDate(this.endDate);
19539 this.updateNavArrows();
19542 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19544 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19545 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19546 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19548 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19549 return parseInt(d, 10);
19552 this.updateNavArrows();
19555 updateNavArrows: function()
19557 if(this.singleMode){
19561 var d = new Date(this.viewDate),
19562 year = d.getUTCFullYear(),
19563 month = d.getUTCMonth();
19565 Roo.each(this.picker().select('.prev', true).elements, function(v){
19567 switch (this.viewMode) {
19570 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19576 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19583 Roo.each(this.picker().select('.next', true).elements, function(v){
19585 switch (this.viewMode) {
19588 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19594 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19602 moveMonth: function(date, dir)
19607 var new_date = new Date(date.valueOf()),
19608 day = new_date.getUTCDate(),
19609 month = new_date.getUTCMonth(),
19610 mag = Math.abs(dir),
19612 dir = dir > 0 ? 1 : -1;
19615 // If going back one month, make sure month is not current month
19616 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19618 return new_date.getUTCMonth() == month;
19620 // If going forward one month, make sure month is as expected
19621 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19623 return new_date.getUTCMonth() != new_month;
19625 new_month = month + dir;
19626 new_date.setUTCMonth(new_month);
19627 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19628 if (new_month < 0 || new_month > 11) {
19629 new_month = (new_month + 12) % 12;
19632 // For magnitudes >1, move one month at a time...
19633 for (var i=0; i<mag; i++) {
19634 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19635 new_date = this.moveMonth(new_date, dir);
19637 // ...then reset the day, keeping it in the new month
19638 new_month = new_date.getUTCMonth();
19639 new_date.setUTCDate(day);
19641 return new_month != new_date.getUTCMonth();
19644 // Common date-resetting loop -- if date is beyond end of month, make it
19647 new_date.setUTCDate(--day);
19648 new_date.setUTCMonth(new_month);
19653 moveYear: function(date, dir)
19655 return this.moveMonth(date, dir*12);
19658 dateWithinRange: function(date)
19660 return date >= this.startDate && date <= this.endDate;
19666 this.picker().remove();
19669 validateValue : function(value)
19671 if(this.getVisibilityEl().hasClass('hidden')){
19675 if(value.length < 1) {
19676 if(this.allowBlank){
19682 if(value.length < this.minLength){
19685 if(value.length > this.maxLength){
19689 var vt = Roo.form.VTypes;
19690 if(!vt[this.vtype](value, this)){
19694 if(typeof this.validator == "function"){
19695 var msg = this.validator(value);
19701 if(this.regex && !this.regex.test(value)){
19705 if(typeof(this.parseDate(value)) == 'undefined'){
19709 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19713 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19723 this.date = this.viewDate = '';
19725 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19730 Roo.apply(Roo.bootstrap.DateField, {
19741 html: '<i class="fa fa-arrow-left"/>'
19751 html: '<i class="fa fa-arrow-right"/>'
19793 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19794 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19795 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19796 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19797 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19810 navFnc: 'FullYear',
19815 navFnc: 'FullYear',
19820 Roo.apply(Roo.bootstrap.DateField, {
19824 cls: 'datepicker dropdown-menu roo-dynamic',
19828 cls: 'datepicker-days',
19832 cls: 'table-condensed',
19834 Roo.bootstrap.DateField.head,
19838 Roo.bootstrap.DateField.footer
19845 cls: 'datepicker-months',
19849 cls: 'table-condensed',
19851 Roo.bootstrap.DateField.head,
19852 Roo.bootstrap.DateField.content,
19853 Roo.bootstrap.DateField.footer
19860 cls: 'datepicker-years',
19864 cls: 'table-condensed',
19866 Roo.bootstrap.DateField.head,
19867 Roo.bootstrap.DateField.content,
19868 Roo.bootstrap.DateField.footer
19887 * @class Roo.bootstrap.TimeField
19888 * @extends Roo.bootstrap.Input
19889 * Bootstrap DateField class
19893 * Create a new TimeField
19894 * @param {Object} config The config object
19897 Roo.bootstrap.TimeField = function(config){
19898 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19902 * Fires when this field show.
19903 * @param {Roo.bootstrap.DateField} thisthis
19904 * @param {Mixed} date The date value
19909 * Fires when this field hide.
19910 * @param {Roo.bootstrap.DateField} this
19911 * @param {Mixed} date The date value
19916 * Fires when select a date.
19917 * @param {Roo.bootstrap.DateField} this
19918 * @param {Mixed} date The date value
19924 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19927 * @cfg {String} format
19928 * The default time format string which can be overriden for localization support. The format must be
19929 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19933 onRender: function(ct, position)
19936 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19938 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19940 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19942 this.pop = this.picker().select('>.datepicker-time',true).first();
19943 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19945 this.picker().on('mousedown', this.onMousedown, this);
19946 this.picker().on('click', this.onClick, this);
19948 this.picker().addClass('datepicker-dropdown');
19953 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19954 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19955 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19956 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19957 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19958 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19962 fireKey: function(e){
19963 if (!this.picker().isVisible()){
19964 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19970 e.preventDefault();
19978 this.onTogglePeriod();
19981 this.onIncrementMinutes();
19984 this.onDecrementMinutes();
19993 onClick: function(e) {
19994 e.stopPropagation();
19995 e.preventDefault();
19998 picker : function()
20000 return this.el.select('.datepicker', true).first();
20003 fillTime: function()
20005 var time = this.pop.select('tbody', true).first();
20007 time.dom.innerHTML = '';
20022 cls: 'hours-up glyphicon glyphicon-chevron-up'
20042 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20063 cls: 'timepicker-hour',
20078 cls: 'timepicker-minute',
20093 cls: 'btn btn-primary period',
20115 cls: 'hours-down glyphicon glyphicon-chevron-down'
20135 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20153 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20160 var hours = this.time.getHours();
20161 var minutes = this.time.getMinutes();
20174 hours = hours - 12;
20178 hours = '0' + hours;
20182 minutes = '0' + minutes;
20185 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20186 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20187 this.pop.select('button', true).first().dom.innerHTML = period;
20193 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20195 var cls = ['bottom'];
20197 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20204 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20209 this.picker().addClass(cls.join('-'));
20213 Roo.each(cls, function(c){
20215 _this.picker().setTop(_this.inputEl().getHeight());
20219 _this.picker().setTop(0 - _this.picker().getHeight());
20224 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20228 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20235 onFocus : function()
20237 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20241 onBlur : function()
20243 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20249 this.picker().show();
20254 this.fireEvent('show', this, this.date);
20259 this.picker().hide();
20262 this.fireEvent('hide', this, this.date);
20265 setTime : function()
20268 this.setValue(this.time.format(this.format));
20270 this.fireEvent('select', this, this.date);
20275 onMousedown: function(e){
20276 e.stopPropagation();
20277 e.preventDefault();
20280 onIncrementHours: function()
20282 Roo.log('onIncrementHours');
20283 this.time = this.time.add(Date.HOUR, 1);
20288 onDecrementHours: function()
20290 Roo.log('onDecrementHours');
20291 this.time = this.time.add(Date.HOUR, -1);
20295 onIncrementMinutes: function()
20297 Roo.log('onIncrementMinutes');
20298 this.time = this.time.add(Date.MINUTE, 1);
20302 onDecrementMinutes: function()
20304 Roo.log('onDecrementMinutes');
20305 this.time = this.time.add(Date.MINUTE, -1);
20309 onTogglePeriod: function()
20311 Roo.log('onTogglePeriod');
20312 this.time = this.time.add(Date.HOUR, 12);
20319 Roo.apply(Roo.bootstrap.TimeField, {
20349 cls: 'btn btn-info ok',
20361 Roo.apply(Roo.bootstrap.TimeField, {
20365 cls: 'datepicker dropdown-menu',
20369 cls: 'datepicker-time',
20373 cls: 'table-condensed',
20375 Roo.bootstrap.TimeField.content,
20376 Roo.bootstrap.TimeField.footer
20395 * @class Roo.bootstrap.MonthField
20396 * @extends Roo.bootstrap.Input
20397 * Bootstrap MonthField class
20399 * @cfg {String} language default en
20402 * Create a new MonthField
20403 * @param {Object} config The config object
20406 Roo.bootstrap.MonthField = function(config){
20407 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20412 * Fires when this field show.
20413 * @param {Roo.bootstrap.MonthField} this
20414 * @param {Mixed} date The date value
20419 * Fires when this field hide.
20420 * @param {Roo.bootstrap.MonthField} this
20421 * @param {Mixed} date The date value
20426 * Fires when select a date.
20427 * @param {Roo.bootstrap.MonthField} this
20428 * @param {String} oldvalue The old value
20429 * @param {String} newvalue The new value
20435 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20437 onRender: function(ct, position)
20440 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20442 this.language = this.language || 'en';
20443 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20444 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20446 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20447 this.isInline = false;
20448 this.isInput = true;
20449 this.component = this.el.select('.add-on', true).first() || false;
20450 this.component = (this.component && this.component.length === 0) ? false : this.component;
20451 this.hasInput = this.component && this.inputEL().length;
20453 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20455 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20457 this.picker().on('mousedown', this.onMousedown, this);
20458 this.picker().on('click', this.onClick, this);
20460 this.picker().addClass('datepicker-dropdown');
20462 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20463 v.setStyle('width', '189px');
20470 if(this.isInline) {
20476 setValue: function(v, suppressEvent)
20478 var o = this.getValue();
20480 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20484 if(suppressEvent !== true){
20485 this.fireEvent('select', this, o, v);
20490 getValue: function()
20495 onClick: function(e)
20497 e.stopPropagation();
20498 e.preventDefault();
20500 var target = e.getTarget();
20502 if(target.nodeName.toLowerCase() === 'i'){
20503 target = Roo.get(target).dom.parentNode;
20506 var nodeName = target.nodeName;
20507 var className = target.className;
20508 var html = target.innerHTML;
20510 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20514 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20516 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20522 picker : function()
20524 return this.pickerEl;
20527 fillMonths: function()
20530 var months = this.picker().select('>.datepicker-months td', true).first();
20532 months.dom.innerHTML = '';
20538 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20541 months.createChild(month);
20550 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20551 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20554 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20555 e.removeClass('active');
20557 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20558 e.addClass('active');
20565 if(this.isInline) {
20569 this.picker().removeClass(['bottom', 'top']);
20571 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20573 * place to the top of element!
20577 this.picker().addClass('top');
20578 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20583 this.picker().addClass('bottom');
20585 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20588 onFocus : function()
20590 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20594 onBlur : function()
20596 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20598 var d = this.inputEl().getValue();
20607 this.picker().show();
20608 this.picker().select('>.datepicker-months', true).first().show();
20612 this.fireEvent('show', this, this.date);
20617 if(this.isInline) {
20620 this.picker().hide();
20621 this.fireEvent('hide', this, this.date);
20625 onMousedown: function(e)
20627 e.stopPropagation();
20628 e.preventDefault();
20633 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20637 fireKey: function(e)
20639 if (!this.picker().isVisible()){
20640 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20651 e.preventDefault();
20655 dir = e.keyCode == 37 ? -1 : 1;
20657 this.vIndex = this.vIndex + dir;
20659 if(this.vIndex < 0){
20663 if(this.vIndex > 11){
20667 if(isNaN(this.vIndex)){
20671 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20677 dir = e.keyCode == 38 ? -1 : 1;
20679 this.vIndex = this.vIndex + dir * 4;
20681 if(this.vIndex < 0){
20685 if(this.vIndex > 11){
20689 if(isNaN(this.vIndex)){
20693 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20698 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20699 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20703 e.preventDefault();
20706 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20707 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20723 this.picker().remove();
20728 Roo.apply(Roo.bootstrap.MonthField, {
20747 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20748 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20753 Roo.apply(Roo.bootstrap.MonthField, {
20757 cls: 'datepicker dropdown-menu roo-dynamic',
20761 cls: 'datepicker-months',
20765 cls: 'table-condensed',
20767 Roo.bootstrap.DateField.content
20787 * @class Roo.bootstrap.CheckBox
20788 * @extends Roo.bootstrap.Input
20789 * Bootstrap CheckBox class
20791 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20792 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20793 * @cfg {String} boxLabel The text that appears beside the checkbox
20794 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20795 * @cfg {Boolean} checked initnal the element
20796 * @cfg {Boolean} inline inline the element (default false)
20797 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20798 * @cfg {String} tooltip label tooltip
20801 * Create a new CheckBox
20802 * @param {Object} config The config object
20805 Roo.bootstrap.CheckBox = function(config){
20806 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20811 * Fires when the element is checked or unchecked.
20812 * @param {Roo.bootstrap.CheckBox} this This input
20813 * @param {Boolean} checked The new checked value
20818 * Fires when the element is click.
20819 * @param {Roo.bootstrap.CheckBox} this This input
20826 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20828 inputType: 'checkbox',
20837 getAutoCreate : function()
20839 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20845 cfg.cls = 'form-group ' + this.inputType; //input-group
20848 cfg.cls += ' ' + this.inputType + '-inline';
20854 type : this.inputType,
20855 value : this.inputValue,
20856 cls : 'roo-' + this.inputType, //'form-box',
20857 placeholder : this.placeholder || ''
20861 if(this.inputType != 'radio'){
20865 cls : 'roo-hidden-value',
20866 value : this.checked ? this.inputValue : this.valueOff
20871 if (this.weight) { // Validity check?
20872 cfg.cls += " " + this.inputType + "-" + this.weight;
20875 if (this.disabled) {
20876 input.disabled=true;
20880 input.checked = this.checked;
20885 input.name = this.name;
20887 if(this.inputType != 'radio'){
20888 hidden.name = this.name;
20889 input.name = '_hidden_' + this.name;
20894 input.cls += ' input-' + this.size;
20899 ['xs','sm','md','lg'].map(function(size){
20900 if (settings[size]) {
20901 cfg.cls += ' col-' + size + '-' + settings[size];
20905 var inputblock = input;
20907 if (this.before || this.after) {
20910 cls : 'input-group',
20915 inputblock.cn.push({
20917 cls : 'input-group-addon',
20922 inputblock.cn.push(input);
20924 if(this.inputType != 'radio'){
20925 inputblock.cn.push(hidden);
20929 inputblock.cn.push({
20931 cls : 'input-group-addon',
20938 if (align ==='left' && this.fieldLabel.length) {
20939 // Roo.log("left and has label");
20944 cls : 'control-label',
20945 html : this.fieldLabel
20955 if(this.labelWidth > 12){
20956 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20959 if(this.labelWidth < 13 && this.labelmd == 0){
20960 this.labelmd = this.labelWidth;
20963 if(this.labellg > 0){
20964 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20965 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20968 if(this.labelmd > 0){
20969 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20970 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20973 if(this.labelsm > 0){
20974 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20975 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20978 if(this.labelxs > 0){
20979 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20980 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20983 } else if ( this.fieldLabel.length) {
20984 // Roo.log(" label");
20988 tag: this.boxLabel ? 'span' : 'label',
20990 cls: 'control-label box-input-label',
20991 //cls : 'input-group-addon',
20992 html : this.fieldLabel
21001 // Roo.log(" no label && no align");
21002 cfg.cn = [ inputblock ] ;
21008 var boxLabelCfg = {
21010 //'for': id, // box label is handled by onclick - so no for...
21012 html: this.boxLabel
21016 boxLabelCfg.tooltip = this.tooltip;
21019 cfg.cn.push(boxLabelCfg);
21022 if(this.inputType != 'radio'){
21023 cfg.cn.push(hidden);
21031 * return the real input element.
21033 inputEl: function ()
21035 return this.el.select('input.roo-' + this.inputType,true).first();
21037 hiddenEl: function ()
21039 return this.el.select('input.roo-hidden-value',true).first();
21042 labelEl: function()
21044 return this.el.select('label.control-label',true).first();
21046 /* depricated... */
21050 return this.labelEl();
21053 boxLabelEl: function()
21055 return this.el.select('label.box-label',true).first();
21058 initEvents : function()
21060 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21062 this.inputEl().on('click', this.onClick, this);
21064 if (this.boxLabel) {
21065 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21068 this.startValue = this.getValue();
21071 Roo.bootstrap.CheckBox.register(this);
21075 onClick : function(e)
21077 if(this.fireEvent('click', this, e) !== false){
21078 this.setChecked(!this.checked);
21083 setChecked : function(state,suppressEvent)
21085 this.startValue = this.getValue();
21087 if(this.inputType == 'radio'){
21089 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21090 e.dom.checked = false;
21093 this.inputEl().dom.checked = true;
21095 this.inputEl().dom.value = this.inputValue;
21097 if(suppressEvent !== true){
21098 this.fireEvent('check', this, true);
21106 this.checked = state;
21108 this.inputEl().dom.checked = state;
21111 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21113 if(suppressEvent !== true){
21114 this.fireEvent('check', this, state);
21120 getValue : function()
21122 if(this.inputType == 'radio'){
21123 return this.getGroupValue();
21126 return this.hiddenEl().dom.value;
21130 getGroupValue : function()
21132 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21136 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21139 setValue : function(v,suppressEvent)
21141 if(this.inputType == 'radio'){
21142 this.setGroupValue(v, suppressEvent);
21146 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21151 setGroupValue : function(v, suppressEvent)
21153 this.startValue = this.getValue();
21155 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21156 e.dom.checked = false;
21158 if(e.dom.value == v){
21159 e.dom.checked = true;
21163 if(suppressEvent !== true){
21164 this.fireEvent('check', this, true);
21172 validate : function()
21174 if(this.getVisibilityEl().hasClass('hidden')){
21180 (this.inputType == 'radio' && this.validateRadio()) ||
21181 (this.inputType == 'checkbox' && this.validateCheckbox())
21187 this.markInvalid();
21191 validateRadio : function()
21193 if(this.getVisibilityEl().hasClass('hidden')){
21197 if(this.allowBlank){
21203 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21204 if(!e.dom.checked){
21216 validateCheckbox : function()
21219 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21220 //return (this.getValue() == this.inputValue) ? true : false;
21223 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21231 for(var i in group){
21232 if(group[i].el.isVisible(true)){
21240 for(var i in group){
21245 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21252 * Mark this field as valid
21254 markValid : function()
21258 this.fireEvent('valid', this);
21260 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21263 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21270 if(this.inputType == 'radio'){
21271 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21272 var fg = e.findParent('.form-group', false, true);
21273 if (Roo.bootstrap.version == 3) {
21274 fg.removeClass([_this.invalidClass, _this.validClass]);
21275 fg.addClass(_this.validClass);
21277 fg.removeClass(['is-valid', 'is-invalid']);
21278 fg.addClass('is-valid');
21286 var fg = this.el.findParent('.form-group', false, true);
21287 if (Roo.bootstrap.version == 3) {
21288 fg.removeClass([this.invalidClass, this.validClass]);
21289 fg.addClass(this.validClass);
21291 fg.removeClass(['is-valid', 'is-invalid']);
21292 fg.addClass('is-valid');
21297 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21303 for(var i in group){
21304 var fg = group[i].el.findParent('.form-group', false, true);
21305 if (Roo.bootstrap.version == 3) {
21306 fg.removeClass([this.invalidClass, this.validClass]);
21307 fg.addClass(this.validClass);
21309 fg.removeClass(['is-valid', 'is-invalid']);
21310 fg.addClass('is-valid');
21316 * Mark this field as invalid
21317 * @param {String} msg The validation message
21319 markInvalid : function(msg)
21321 if(this.allowBlank){
21327 this.fireEvent('invalid', this, msg);
21329 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21332 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21336 label.markInvalid();
21339 if(this.inputType == 'radio'){
21341 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21342 var fg = e.findParent('.form-group', false, true);
21343 if (Roo.bootstrap.version == 3) {
21344 fg.removeClass([_this.invalidClass, _this.validClass]);
21345 fg.addClass(_this.invalidClass);
21347 fg.removeClass(['is-invalid', 'is-valid']);
21348 fg.addClass('is-invalid');
21356 var fg = this.el.findParent('.form-group', false, true);
21357 if (Roo.bootstrap.version == 3) {
21358 fg.removeClass([_this.invalidClass, _this.validClass]);
21359 fg.addClass(_this.invalidClass);
21361 fg.removeClass(['is-invalid', 'is-valid']);
21362 fg.addClass('is-invalid');
21367 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21373 for(var i in group){
21374 var fg = group[i].el.findParent('.form-group', false, true);
21375 if (Roo.bootstrap.version == 3) {
21376 fg.removeClass([_this.invalidClass, _this.validClass]);
21377 fg.addClass(_this.invalidClass);
21379 fg.removeClass(['is-invalid', 'is-valid']);
21380 fg.addClass('is-invalid');
21386 clearInvalid : function()
21388 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21390 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21392 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21394 if (label && label.iconEl) {
21395 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21396 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21400 disable : function()
21402 if(this.inputType != 'radio'){
21403 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21410 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21411 _this.getActionEl().addClass(this.disabledClass);
21412 e.dom.disabled = true;
21416 this.disabled = true;
21417 this.fireEvent("disable", this);
21421 enable : function()
21423 if(this.inputType != 'radio'){
21424 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21431 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21432 _this.getActionEl().removeClass(this.disabledClass);
21433 e.dom.disabled = false;
21437 this.disabled = false;
21438 this.fireEvent("enable", this);
21442 setBoxLabel : function(v)
21447 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21453 Roo.apply(Roo.bootstrap.CheckBox, {
21458 * register a CheckBox Group
21459 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21461 register : function(checkbox)
21463 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21464 this.groups[checkbox.groupId] = {};
21467 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21471 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21475 * fetch a CheckBox Group based on the group ID
21476 * @param {string} the group ID
21477 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21479 get: function(groupId) {
21480 if (typeof(this.groups[groupId]) == 'undefined') {
21484 return this.groups[groupId] ;
21497 * @class Roo.bootstrap.Radio
21498 * @extends Roo.bootstrap.Component
21499 * Bootstrap Radio class
21500 * @cfg {String} boxLabel - the label associated
21501 * @cfg {String} value - the value of radio
21504 * Create a new Radio
21505 * @param {Object} config The config object
21507 Roo.bootstrap.Radio = function(config){
21508 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21512 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21518 getAutoCreate : function()
21522 cls : 'form-group radio',
21527 html : this.boxLabel
21535 initEvents : function()
21537 this.parent().register(this);
21539 this.el.on('click', this.onClick, this);
21543 onClick : function(e)
21545 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21546 this.setChecked(true);
21550 setChecked : function(state, suppressEvent)
21552 this.parent().setValue(this.value, suppressEvent);
21556 setBoxLabel : function(v)
21561 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21576 * @class Roo.bootstrap.SecurePass
21577 * @extends Roo.bootstrap.Input
21578 * Bootstrap SecurePass class
21582 * Create a new SecurePass
21583 * @param {Object} config The config object
21586 Roo.bootstrap.SecurePass = function (config) {
21587 // these go here, so the translation tool can replace them..
21589 PwdEmpty: "Please type a password, and then retype it to confirm.",
21590 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21591 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21592 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21593 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21594 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21595 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21596 TooWeak: "Your password is Too Weak."
21598 this.meterLabel = "Password strength:";
21599 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21600 this.meterClass = [
21601 "roo-password-meter-tooweak",
21602 "roo-password-meter-weak",
21603 "roo-password-meter-medium",
21604 "roo-password-meter-strong",
21605 "roo-password-meter-grey"
21610 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21613 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21615 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21617 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21618 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21619 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21620 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21621 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21622 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21623 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21633 * @cfg {String/Object} Label for the strength meter (defaults to
21634 * 'Password strength:')
21639 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21640 * ['Weak', 'Medium', 'Strong'])
21643 pwdStrengths: false,
21656 initEvents: function ()
21658 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21660 if (this.el.is('input[type=password]') && Roo.isSafari) {
21661 this.el.on('keydown', this.SafariOnKeyDown, this);
21664 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21667 onRender: function (ct, position)
21669 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21670 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21671 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21673 this.trigger.createChild({
21678 cls: 'roo-password-meter-grey col-xs-12',
21681 //width: this.meterWidth + 'px'
21685 cls: 'roo-password-meter-text'
21691 if (this.hideTrigger) {
21692 this.trigger.setDisplayed(false);
21694 this.setSize(this.width || '', this.height || '');
21697 onDestroy: function ()
21699 if (this.trigger) {
21700 this.trigger.removeAllListeners();
21701 this.trigger.remove();
21704 this.wrap.remove();
21706 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21709 checkStrength: function ()
21711 var pwd = this.inputEl().getValue();
21712 if (pwd == this._lastPwd) {
21717 if (this.ClientSideStrongPassword(pwd)) {
21719 } else if (this.ClientSideMediumPassword(pwd)) {
21721 } else if (this.ClientSideWeakPassword(pwd)) {
21727 Roo.log('strength1: ' + strength);
21729 //var pm = this.trigger.child('div/div/div').dom;
21730 var pm = this.trigger.child('div/div');
21731 pm.removeClass(this.meterClass);
21732 pm.addClass(this.meterClass[strength]);
21735 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21737 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21739 this._lastPwd = pwd;
21743 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21745 this._lastPwd = '';
21747 var pm = this.trigger.child('div/div');
21748 pm.removeClass(this.meterClass);
21749 pm.addClass('roo-password-meter-grey');
21752 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21755 this.inputEl().dom.type='password';
21758 validateValue: function (value)
21761 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21764 if (value.length == 0) {
21765 if (this.allowBlank) {
21766 this.clearInvalid();
21770 this.markInvalid(this.errors.PwdEmpty);
21771 this.errorMsg = this.errors.PwdEmpty;
21779 if ('[\x21-\x7e]*'.match(value)) {
21780 this.markInvalid(this.errors.PwdBadChar);
21781 this.errorMsg = this.errors.PwdBadChar;
21784 if (value.length < 6) {
21785 this.markInvalid(this.errors.PwdShort);
21786 this.errorMsg = this.errors.PwdShort;
21789 if (value.length > 16) {
21790 this.markInvalid(this.errors.PwdLong);
21791 this.errorMsg = this.errors.PwdLong;
21795 if (this.ClientSideStrongPassword(value)) {
21797 } else if (this.ClientSideMediumPassword(value)) {
21799 } else if (this.ClientSideWeakPassword(value)) {
21806 if (strength < 2) {
21807 //this.markInvalid(this.errors.TooWeak);
21808 this.errorMsg = this.errors.TooWeak;
21813 console.log('strength2: ' + strength);
21815 //var pm = this.trigger.child('div/div/div').dom;
21817 var pm = this.trigger.child('div/div');
21818 pm.removeClass(this.meterClass);
21819 pm.addClass(this.meterClass[strength]);
21821 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21823 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21825 this.errorMsg = '';
21829 CharacterSetChecks: function (type)
21832 this.fResult = false;
21835 isctype: function (character, type)
21838 case this.kCapitalLetter:
21839 if (character >= 'A' && character <= 'Z') {
21844 case this.kSmallLetter:
21845 if (character >= 'a' && character <= 'z') {
21851 if (character >= '0' && character <= '9') {
21856 case this.kPunctuation:
21857 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21868 IsLongEnough: function (pwd, size)
21870 return !(pwd == null || isNaN(size) || pwd.length < size);
21873 SpansEnoughCharacterSets: function (word, nb)
21875 if (!this.IsLongEnough(word, nb))
21880 var characterSetChecks = new Array(
21881 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21882 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21885 for (var index = 0; index < word.length; ++index) {
21886 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21887 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21888 characterSetChecks[nCharSet].fResult = true;
21895 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21896 if (characterSetChecks[nCharSet].fResult) {
21901 if (nCharSets < nb) {
21907 ClientSideStrongPassword: function (pwd)
21909 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21912 ClientSideMediumPassword: function (pwd)
21914 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21917 ClientSideWeakPassword: function (pwd)
21919 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21922 })//<script type="text/javascript">
21925 * Based Ext JS Library 1.1.1
21926 * Copyright(c) 2006-2007, Ext JS, LLC.
21932 * @class Roo.HtmlEditorCore
21933 * @extends Roo.Component
21934 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21936 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21939 Roo.HtmlEditorCore = function(config){
21942 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21947 * @event initialize
21948 * Fires when the editor is fully initialized (including the iframe)
21949 * @param {Roo.HtmlEditorCore} this
21954 * Fires when the editor is first receives the focus. Any insertion must wait
21955 * until after this event.
21956 * @param {Roo.HtmlEditorCore} this
21960 * @event beforesync
21961 * Fires before the textarea is updated with content from the editor iframe. Return false
21962 * to cancel the sync.
21963 * @param {Roo.HtmlEditorCore} this
21964 * @param {String} html
21968 * @event beforepush
21969 * Fires before the iframe editor is updated with content from the textarea. Return false
21970 * to cancel the push.
21971 * @param {Roo.HtmlEditorCore} this
21972 * @param {String} html
21977 * Fires when the textarea is updated with content from the editor iframe.
21978 * @param {Roo.HtmlEditorCore} this
21979 * @param {String} html
21984 * Fires when the iframe editor is updated with content from the textarea.
21985 * @param {Roo.HtmlEditorCore} this
21986 * @param {String} html
21991 * @event editorevent
21992 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21993 * @param {Roo.HtmlEditorCore} this
21999 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22001 // defaults : white / black...
22002 this.applyBlacklists();
22009 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22013 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22019 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22024 * @cfg {Number} height (in pixels)
22028 * @cfg {Number} width (in pixels)
22033 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22036 stylesheets: false,
22041 // private properties
22042 validationEvent : false,
22044 initialized : false,
22046 sourceEditMode : false,
22047 onFocus : Roo.emptyFn,
22049 hideMode:'offsets',
22053 // blacklist + whitelisted elements..
22060 * Protected method that will not generally be called directly. It
22061 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22062 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22064 getDocMarkup : function(){
22068 // inherit styels from page...??
22069 if (this.stylesheets === false) {
22071 Roo.get(document.head).select('style').each(function(node) {
22072 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22075 Roo.get(document.head).select('link').each(function(node) {
22076 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22079 } else if (!this.stylesheets.length) {
22081 st = '<style type="text/css">' +
22082 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22085 st = '<style type="text/css">' +
22090 st += '<style type="text/css">' +
22091 'IMG { cursor: pointer } ' +
22094 var cls = 'roo-htmleditor-body';
22096 if(this.bodyCls.length){
22097 cls += ' ' + this.bodyCls;
22100 return '<html><head>' + st +
22101 //<style type="text/css">' +
22102 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22104 ' </head><body class="' + cls + '"></body></html>';
22108 onRender : function(ct, position)
22111 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22112 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22115 this.el.dom.style.border = '0 none';
22116 this.el.dom.setAttribute('tabIndex', -1);
22117 this.el.addClass('x-hidden hide');
22121 if(Roo.isIE){ // fix IE 1px bogus margin
22122 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22126 this.frameId = Roo.id();
22130 var iframe = this.owner.wrap.createChild({
22132 cls: 'form-control', // bootstrap..
22134 name: this.frameId,
22135 frameBorder : 'no',
22136 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22141 this.iframe = iframe.dom;
22143 this.assignDocWin();
22145 this.doc.designMode = 'on';
22148 this.doc.write(this.getDocMarkup());
22152 var task = { // must defer to wait for browser to be ready
22154 //console.log("run task?" + this.doc.readyState);
22155 this.assignDocWin();
22156 if(this.doc.body || this.doc.readyState == 'complete'){
22158 this.doc.designMode="on";
22162 Roo.TaskMgr.stop(task);
22163 this.initEditor.defer(10, this);
22170 Roo.TaskMgr.start(task);
22175 onResize : function(w, h)
22177 Roo.log('resize: ' +w + ',' + h );
22178 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22182 if(typeof w == 'number'){
22184 this.iframe.style.width = w + 'px';
22186 if(typeof h == 'number'){
22188 this.iframe.style.height = h + 'px';
22190 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22197 * Toggles the editor between standard and source edit mode.
22198 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22200 toggleSourceEdit : function(sourceEditMode){
22202 this.sourceEditMode = sourceEditMode === true;
22204 if(this.sourceEditMode){
22206 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22209 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22210 //this.iframe.className = '';
22213 //this.setSize(this.owner.wrap.getSize());
22214 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22221 * Protected method that will not generally be called directly. If you need/want
22222 * custom HTML cleanup, this is the method you should override.
22223 * @param {String} html The HTML to be cleaned
22224 * return {String} The cleaned HTML
22226 cleanHtml : function(html){
22227 html = String(html);
22228 if(html.length > 5){
22229 if(Roo.isSafari){ // strip safari nonsense
22230 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22233 if(html == ' '){
22240 * HTML Editor -> Textarea
22241 * Protected method that will not generally be called directly. Syncs the contents
22242 * of the editor iframe with the textarea.
22244 syncValue : function(){
22245 if(this.initialized){
22246 var bd = (this.doc.body || this.doc.documentElement);
22247 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22248 var html = bd.innerHTML;
22250 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22251 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22253 html = '<div style="'+m[0]+'">' + html + '</div>';
22256 html = this.cleanHtml(html);
22257 // fix up the special chars.. normaly like back quotes in word...
22258 // however we do not want to do this with chinese..
22259 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22260 var cc = b.charCodeAt();
22262 (cc >= 0x4E00 && cc < 0xA000 ) ||
22263 (cc >= 0x3400 && cc < 0x4E00 ) ||
22264 (cc >= 0xf900 && cc < 0xfb00 )
22270 if(this.owner.fireEvent('beforesync', this, html) !== false){
22271 this.el.dom.value = html;
22272 this.owner.fireEvent('sync', this, html);
22278 * Protected method that will not generally be called directly. Pushes the value of the textarea
22279 * into the iframe editor.
22281 pushValue : function(){
22282 if(this.initialized){
22283 var v = this.el.dom.value.trim();
22285 // if(v.length < 1){
22289 if(this.owner.fireEvent('beforepush', this, v) !== false){
22290 var d = (this.doc.body || this.doc.documentElement);
22292 this.cleanUpPaste();
22293 this.el.dom.value = d.innerHTML;
22294 this.owner.fireEvent('push', this, v);
22300 deferFocus : function(){
22301 this.focus.defer(10, this);
22305 focus : function(){
22306 if(this.win && !this.sourceEditMode){
22313 assignDocWin: function()
22315 var iframe = this.iframe;
22318 this.doc = iframe.contentWindow.document;
22319 this.win = iframe.contentWindow;
22321 // if (!Roo.get(this.frameId)) {
22324 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22325 // this.win = Roo.get(this.frameId).dom.contentWindow;
22327 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22331 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22332 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22337 initEditor : function(){
22338 //console.log("INIT EDITOR");
22339 this.assignDocWin();
22343 this.doc.designMode="on";
22345 this.doc.write(this.getDocMarkup());
22348 var dbody = (this.doc.body || this.doc.documentElement);
22349 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22350 // this copies styles from the containing element into thsi one..
22351 // not sure why we need all of this..
22352 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22354 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22355 //ss['background-attachment'] = 'fixed'; // w3c
22356 dbody.bgProperties = 'fixed'; // ie
22357 //Roo.DomHelper.applyStyles(dbody, ss);
22358 Roo.EventManager.on(this.doc, {
22359 //'mousedown': this.onEditorEvent,
22360 'mouseup': this.onEditorEvent,
22361 'dblclick': this.onEditorEvent,
22362 'click': this.onEditorEvent,
22363 'keyup': this.onEditorEvent,
22368 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22370 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22371 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22373 this.initialized = true;
22375 this.owner.fireEvent('initialize', this);
22380 onDestroy : function(){
22386 //for (var i =0; i < this.toolbars.length;i++) {
22387 // // fixme - ask toolbars for heights?
22388 // this.toolbars[i].onDestroy();
22391 //this.wrap.dom.innerHTML = '';
22392 //this.wrap.remove();
22397 onFirstFocus : function(){
22399 this.assignDocWin();
22402 this.activated = true;
22405 if(Roo.isGecko){ // prevent silly gecko errors
22407 var s = this.win.getSelection();
22408 if(!s.focusNode || s.focusNode.nodeType != 3){
22409 var r = s.getRangeAt(0);
22410 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22415 this.execCmd('useCSS', true);
22416 this.execCmd('styleWithCSS', false);
22419 this.owner.fireEvent('activate', this);
22423 adjustFont: function(btn){
22424 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22425 //if(Roo.isSafari){ // safari
22428 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22429 if(Roo.isSafari){ // safari
22430 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22431 v = (v < 10) ? 10 : v;
22432 v = (v > 48) ? 48 : v;
22433 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22438 v = Math.max(1, v+adjust);
22440 this.execCmd('FontSize', v );
22443 onEditorEvent : function(e)
22445 this.owner.fireEvent('editorevent', this, e);
22446 // this.updateToolbar();
22447 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22450 insertTag : function(tg)
22452 // could be a bit smarter... -> wrap the current selected tRoo..
22453 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22455 range = this.createRange(this.getSelection());
22456 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22457 wrappingNode.appendChild(range.extractContents());
22458 range.insertNode(wrappingNode);
22465 this.execCmd("formatblock", tg);
22469 insertText : function(txt)
22473 var range = this.createRange();
22474 range.deleteContents();
22475 //alert(Sender.getAttribute('label'));
22477 range.insertNode(this.doc.createTextNode(txt));
22483 * Executes a Midas editor command on the editor document and performs necessary focus and
22484 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22485 * @param {String} cmd The Midas command
22486 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22488 relayCmd : function(cmd, value){
22490 this.execCmd(cmd, value);
22491 this.owner.fireEvent('editorevent', this);
22492 //this.updateToolbar();
22493 this.owner.deferFocus();
22497 * Executes a Midas editor command directly on the editor document.
22498 * For visual commands, you should use {@link #relayCmd} instead.
22499 * <b>This should only be called after the editor is initialized.</b>
22500 * @param {String} cmd The Midas command
22501 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22503 execCmd : function(cmd, value){
22504 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22511 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22513 * @param {String} text | dom node..
22515 insertAtCursor : function(text)
22518 if(!this.activated){
22524 var r = this.doc.selection.createRange();
22535 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22539 // from jquery ui (MIT licenced)
22541 var win = this.win;
22543 if (win.getSelection && win.getSelection().getRangeAt) {
22544 range = win.getSelection().getRangeAt(0);
22545 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22546 range.insertNode(node);
22547 } else if (win.document.selection && win.document.selection.createRange) {
22548 // no firefox support
22549 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22550 win.document.selection.createRange().pasteHTML(txt);
22552 // no firefox support
22553 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22554 this.execCmd('InsertHTML', txt);
22563 mozKeyPress : function(e){
22565 var c = e.getCharCode(), cmd;
22568 c = String.fromCharCode(c).toLowerCase();
22582 this.cleanUpPaste.defer(100, this);
22590 e.preventDefault();
22598 fixKeys : function(){ // load time branching for fastest keydown performance
22600 return function(e){
22601 var k = e.getKey(), r;
22604 r = this.doc.selection.createRange();
22607 r.pasteHTML('    ');
22614 r = this.doc.selection.createRange();
22616 var target = r.parentElement();
22617 if(!target || target.tagName.toLowerCase() != 'li'){
22619 r.pasteHTML('<br />');
22625 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22626 this.cleanUpPaste.defer(100, this);
22632 }else if(Roo.isOpera){
22633 return function(e){
22634 var k = e.getKey();
22638 this.execCmd('InsertHTML','    ');
22641 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22642 this.cleanUpPaste.defer(100, this);
22647 }else if(Roo.isSafari){
22648 return function(e){
22649 var k = e.getKey();
22653 this.execCmd('InsertText','\t');
22657 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22658 this.cleanUpPaste.defer(100, this);
22666 getAllAncestors: function()
22668 var p = this.getSelectedNode();
22671 a.push(p); // push blank onto stack..
22672 p = this.getParentElement();
22676 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22680 a.push(this.doc.body);
22684 lastSelNode : false,
22687 getSelection : function()
22689 this.assignDocWin();
22690 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22693 getSelectedNode: function()
22695 // this may only work on Gecko!!!
22697 // should we cache this!!!!
22702 var range = this.createRange(this.getSelection()).cloneRange();
22705 var parent = range.parentElement();
22707 var testRange = range.duplicate();
22708 testRange.moveToElementText(parent);
22709 if (testRange.inRange(range)) {
22712 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22715 parent = parent.parentElement;
22720 // is ancestor a text element.
22721 var ac = range.commonAncestorContainer;
22722 if (ac.nodeType == 3) {
22723 ac = ac.parentNode;
22726 var ar = ac.childNodes;
22729 var other_nodes = [];
22730 var has_other_nodes = false;
22731 for (var i=0;i<ar.length;i++) {
22732 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22735 // fullly contained node.
22737 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22742 // probably selected..
22743 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22744 other_nodes.push(ar[i]);
22748 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22753 has_other_nodes = true;
22755 if (!nodes.length && other_nodes.length) {
22756 nodes= other_nodes;
22758 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22764 createRange: function(sel)
22766 // this has strange effects when using with
22767 // top toolbar - not sure if it's a great idea.
22768 //this.editor.contentWindow.focus();
22769 if (typeof sel != "undefined") {
22771 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22773 return this.doc.createRange();
22776 return this.doc.createRange();
22779 getParentElement: function()
22782 this.assignDocWin();
22783 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22785 var range = this.createRange(sel);
22788 var p = range.commonAncestorContainer;
22789 while (p.nodeType == 3) { // text node
22800 * Range intersection.. the hard stuff...
22804 * [ -- selected range --- ]
22808 * if end is before start or hits it. fail.
22809 * if start is after end or hits it fail.
22811 * if either hits (but other is outside. - then it's not
22817 // @see http://www.thismuchiknow.co.uk/?p=64.
22818 rangeIntersectsNode : function(range, node)
22820 var nodeRange = node.ownerDocument.createRange();
22822 nodeRange.selectNode(node);
22824 nodeRange.selectNodeContents(node);
22827 var rangeStartRange = range.cloneRange();
22828 rangeStartRange.collapse(true);
22830 var rangeEndRange = range.cloneRange();
22831 rangeEndRange.collapse(false);
22833 var nodeStartRange = nodeRange.cloneRange();
22834 nodeStartRange.collapse(true);
22836 var nodeEndRange = nodeRange.cloneRange();
22837 nodeEndRange.collapse(false);
22839 return rangeStartRange.compareBoundaryPoints(
22840 Range.START_TO_START, nodeEndRange) == -1 &&
22841 rangeEndRange.compareBoundaryPoints(
22842 Range.START_TO_START, nodeStartRange) == 1;
22846 rangeCompareNode : function(range, node)
22848 var nodeRange = node.ownerDocument.createRange();
22850 nodeRange.selectNode(node);
22852 nodeRange.selectNodeContents(node);
22856 range.collapse(true);
22858 nodeRange.collapse(true);
22860 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22861 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22863 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22865 var nodeIsBefore = ss == 1;
22866 var nodeIsAfter = ee == -1;
22868 if (nodeIsBefore && nodeIsAfter) {
22871 if (!nodeIsBefore && nodeIsAfter) {
22872 return 1; //right trailed.
22875 if (nodeIsBefore && !nodeIsAfter) {
22876 return 2; // left trailed.
22882 // private? - in a new class?
22883 cleanUpPaste : function()
22885 // cleans up the whole document..
22886 Roo.log('cleanuppaste');
22888 this.cleanUpChildren(this.doc.body);
22889 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22890 if (clean != this.doc.body.innerHTML) {
22891 this.doc.body.innerHTML = clean;
22896 cleanWordChars : function(input) {// change the chars to hex code
22897 var he = Roo.HtmlEditorCore;
22899 var output = input;
22900 Roo.each(he.swapCodes, function(sw) {
22901 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22903 output = output.replace(swapper, sw[1]);
22910 cleanUpChildren : function (n)
22912 if (!n.childNodes.length) {
22915 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22916 this.cleanUpChild(n.childNodes[i]);
22923 cleanUpChild : function (node)
22926 //console.log(node);
22927 if (node.nodeName == "#text") {
22928 // clean up silly Windows -- stuff?
22931 if (node.nodeName == "#comment") {
22932 node.parentNode.removeChild(node);
22933 // clean up silly Windows -- stuff?
22936 var lcname = node.tagName.toLowerCase();
22937 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22938 // whitelist of tags..
22940 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22942 node.parentNode.removeChild(node);
22947 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22949 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22950 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22952 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22953 // remove_keep_children = true;
22956 if (remove_keep_children) {
22957 this.cleanUpChildren(node);
22958 // inserts everything just before this node...
22959 while (node.childNodes.length) {
22960 var cn = node.childNodes[0];
22961 node.removeChild(cn);
22962 node.parentNode.insertBefore(cn, node);
22964 node.parentNode.removeChild(node);
22968 if (!node.attributes || !node.attributes.length) {
22969 this.cleanUpChildren(node);
22973 function cleanAttr(n,v)
22976 if (v.match(/^\./) || v.match(/^\//)) {
22979 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22982 if (v.match(/^#/)) {
22985 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22986 node.removeAttribute(n);
22990 var cwhite = this.cwhite;
22991 var cblack = this.cblack;
22993 function cleanStyle(n,v)
22995 if (v.match(/expression/)) { //XSS?? should we even bother..
22996 node.removeAttribute(n);
23000 var parts = v.split(/;/);
23003 Roo.each(parts, function(p) {
23004 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23008 var l = p.split(':').shift().replace(/\s+/g,'');
23009 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23011 if ( cwhite.length && cblack.indexOf(l) > -1) {
23012 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23013 //node.removeAttribute(n);
23017 // only allow 'c whitelisted system attributes'
23018 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23019 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23020 //node.removeAttribute(n);
23030 if (clean.length) {
23031 node.setAttribute(n, clean.join(';'));
23033 node.removeAttribute(n);
23039 for (var i = node.attributes.length-1; i > -1 ; i--) {
23040 var a = node.attributes[i];
23043 if (a.name.toLowerCase().substr(0,2)=='on') {
23044 node.removeAttribute(a.name);
23047 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23048 node.removeAttribute(a.name);
23051 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23052 cleanAttr(a.name,a.value); // fixme..
23055 if (a.name == 'style') {
23056 cleanStyle(a.name,a.value);
23059 /// clean up MS crap..
23060 // tecnically this should be a list of valid class'es..
23063 if (a.name == 'class') {
23064 if (a.value.match(/^Mso/)) {
23065 node.className = '';
23068 if (a.value.match(/^body$/)) {
23069 node.className = '';
23080 this.cleanUpChildren(node);
23086 * Clean up MS wordisms...
23088 cleanWord : function(node)
23093 this.cleanWord(this.doc.body);
23096 if (node.nodeName == "#text") {
23097 // clean up silly Windows -- stuff?
23100 if (node.nodeName == "#comment") {
23101 node.parentNode.removeChild(node);
23102 // clean up silly Windows -- stuff?
23106 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23107 node.parentNode.removeChild(node);
23111 // remove - but keep children..
23112 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23113 while (node.childNodes.length) {
23114 var cn = node.childNodes[0];
23115 node.removeChild(cn);
23116 node.parentNode.insertBefore(cn, node);
23118 node.parentNode.removeChild(node);
23119 this.iterateChildren(node, this.cleanWord);
23123 if (node.className.length) {
23125 var cn = node.className.split(/\W+/);
23127 Roo.each(cn, function(cls) {
23128 if (cls.match(/Mso[a-zA-Z]+/)) {
23133 node.className = cna.length ? cna.join(' ') : '';
23135 node.removeAttribute("class");
23139 if (node.hasAttribute("lang")) {
23140 node.removeAttribute("lang");
23143 if (node.hasAttribute("style")) {
23145 var styles = node.getAttribute("style").split(";");
23147 Roo.each(styles, function(s) {
23148 if (!s.match(/:/)) {
23151 var kv = s.split(":");
23152 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23155 // what ever is left... we allow.
23158 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23159 if (!nstyle.length) {
23160 node.removeAttribute('style');
23163 this.iterateChildren(node, this.cleanWord);
23169 * iterateChildren of a Node, calling fn each time, using this as the scole..
23170 * @param {DomNode} node node to iterate children of.
23171 * @param {Function} fn method of this class to call on each item.
23173 iterateChildren : function(node, fn)
23175 if (!node.childNodes.length) {
23178 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23179 fn.call(this, node.childNodes[i])
23185 * cleanTableWidths.
23187 * Quite often pasting from word etc.. results in tables with column and widths.
23188 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23191 cleanTableWidths : function(node)
23196 this.cleanTableWidths(this.doc.body);
23201 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23204 Roo.log(node.tagName);
23205 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23206 this.iterateChildren(node, this.cleanTableWidths);
23209 if (node.hasAttribute('width')) {
23210 node.removeAttribute('width');
23214 if (node.hasAttribute("style")) {
23217 var styles = node.getAttribute("style").split(";");
23219 Roo.each(styles, function(s) {
23220 if (!s.match(/:/)) {
23223 var kv = s.split(":");
23224 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23227 // what ever is left... we allow.
23230 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23231 if (!nstyle.length) {
23232 node.removeAttribute('style');
23236 this.iterateChildren(node, this.cleanTableWidths);
23244 domToHTML : function(currentElement, depth, nopadtext) {
23246 depth = depth || 0;
23247 nopadtext = nopadtext || false;
23249 if (!currentElement) {
23250 return this.domToHTML(this.doc.body);
23253 //Roo.log(currentElement);
23255 var allText = false;
23256 var nodeName = currentElement.nodeName;
23257 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23259 if (nodeName == '#text') {
23261 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23266 if (nodeName != 'BODY') {
23269 // Prints the node tagName, such as <A>, <IMG>, etc
23272 for(i = 0; i < currentElement.attributes.length;i++) {
23274 var aname = currentElement.attributes.item(i).name;
23275 if (!currentElement.attributes.item(i).value.length) {
23278 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23281 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23290 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23293 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23298 // Traverse the tree
23300 var currentElementChild = currentElement.childNodes.item(i);
23301 var allText = true;
23302 var innerHTML = '';
23304 while (currentElementChild) {
23305 // Formatting code (indent the tree so it looks nice on the screen)
23306 var nopad = nopadtext;
23307 if (lastnode == 'SPAN') {
23311 if (currentElementChild.nodeName == '#text') {
23312 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23313 toadd = nopadtext ? toadd : toadd.trim();
23314 if (!nopad && toadd.length > 80) {
23315 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23317 innerHTML += toadd;
23320 currentElementChild = currentElement.childNodes.item(i);
23326 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23328 // Recursively traverse the tree structure of the child node
23329 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23330 lastnode = currentElementChild.nodeName;
23332 currentElementChild=currentElement.childNodes.item(i);
23338 // The remaining code is mostly for formatting the tree
23339 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23344 ret+= "</"+tagName+">";
23350 applyBlacklists : function()
23352 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23353 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23357 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23358 if (b.indexOf(tag) > -1) {
23361 this.white.push(tag);
23365 Roo.each(w, function(tag) {
23366 if (b.indexOf(tag) > -1) {
23369 if (this.white.indexOf(tag) > -1) {
23372 this.white.push(tag);
23377 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23378 if (w.indexOf(tag) > -1) {
23381 this.black.push(tag);
23385 Roo.each(b, function(tag) {
23386 if (w.indexOf(tag) > -1) {
23389 if (this.black.indexOf(tag) > -1) {
23392 this.black.push(tag);
23397 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23398 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23402 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23403 if (b.indexOf(tag) > -1) {
23406 this.cwhite.push(tag);
23410 Roo.each(w, function(tag) {
23411 if (b.indexOf(tag) > -1) {
23414 if (this.cwhite.indexOf(tag) > -1) {
23417 this.cwhite.push(tag);
23422 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23423 if (w.indexOf(tag) > -1) {
23426 this.cblack.push(tag);
23430 Roo.each(b, function(tag) {
23431 if (w.indexOf(tag) > -1) {
23434 if (this.cblack.indexOf(tag) > -1) {
23437 this.cblack.push(tag);
23442 setStylesheets : function(stylesheets)
23444 if(typeof(stylesheets) == 'string'){
23445 Roo.get(this.iframe.contentDocument.head).createChild({
23447 rel : 'stylesheet',
23456 Roo.each(stylesheets, function(s) {
23461 Roo.get(_this.iframe.contentDocument.head).createChild({
23463 rel : 'stylesheet',
23472 removeStylesheets : function()
23476 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23481 setStyle : function(style)
23483 Roo.get(this.iframe.contentDocument.head).createChild({
23492 // hide stuff that is not compatible
23506 * @event specialkey
23510 * @cfg {String} fieldClass @hide
23513 * @cfg {String} focusClass @hide
23516 * @cfg {String} autoCreate @hide
23519 * @cfg {String} inputType @hide
23522 * @cfg {String} invalidClass @hide
23525 * @cfg {String} invalidText @hide
23528 * @cfg {String} msgFx @hide
23531 * @cfg {String} validateOnBlur @hide
23535 Roo.HtmlEditorCore.white = [
23536 'area', 'br', 'img', 'input', 'hr', 'wbr',
23538 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23539 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23540 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23541 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23542 'table', 'ul', 'xmp',
23544 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23547 'dir', 'menu', 'ol', 'ul', 'dl',
23553 Roo.HtmlEditorCore.black = [
23554 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23556 'base', 'basefont', 'bgsound', 'blink', 'body',
23557 'frame', 'frameset', 'head', 'html', 'ilayer',
23558 'iframe', 'layer', 'link', 'meta', 'object',
23559 'script', 'style' ,'title', 'xml' // clean later..
23561 Roo.HtmlEditorCore.clean = [
23562 'script', 'style', 'title', 'xml'
23564 Roo.HtmlEditorCore.remove = [
23569 Roo.HtmlEditorCore.ablack = [
23573 Roo.HtmlEditorCore.aclean = [
23574 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23578 Roo.HtmlEditorCore.pwhite= [
23579 'http', 'https', 'mailto'
23582 // white listed style attributes.
23583 Roo.HtmlEditorCore.cwhite= [
23584 // 'text-align', /// default is to allow most things..
23590 // black listed style attributes.
23591 Roo.HtmlEditorCore.cblack= [
23592 // 'font-size' -- this can be set by the project
23596 Roo.HtmlEditorCore.swapCodes =[
23615 * @class Roo.bootstrap.HtmlEditor
23616 * @extends Roo.bootstrap.TextArea
23617 * Bootstrap HtmlEditor class
23620 * Create a new HtmlEditor
23621 * @param {Object} config The config object
23624 Roo.bootstrap.HtmlEditor = function(config){
23625 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23626 if (!this.toolbars) {
23627 this.toolbars = [];
23630 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23633 * @event initialize
23634 * Fires when the editor is fully initialized (including the iframe)
23635 * @param {HtmlEditor} this
23640 * Fires when the editor is first receives the focus. Any insertion must wait
23641 * until after this event.
23642 * @param {HtmlEditor} this
23646 * @event beforesync
23647 * Fires before the textarea is updated with content from the editor iframe. Return false
23648 * to cancel the sync.
23649 * @param {HtmlEditor} this
23650 * @param {String} html
23654 * @event beforepush
23655 * Fires before the iframe editor is updated with content from the textarea. Return false
23656 * to cancel the push.
23657 * @param {HtmlEditor} this
23658 * @param {String} html
23663 * Fires when the textarea is updated with content from the editor iframe.
23664 * @param {HtmlEditor} this
23665 * @param {String} html
23670 * Fires when the iframe editor is updated with content from the textarea.
23671 * @param {HtmlEditor} this
23672 * @param {String} html
23676 * @event editmodechange
23677 * Fires when the editor switches edit modes
23678 * @param {HtmlEditor} this
23679 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23681 editmodechange: true,
23683 * @event editorevent
23684 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23685 * @param {HtmlEditor} this
23689 * @event firstfocus
23690 * Fires when on first focus - needed by toolbars..
23691 * @param {HtmlEditor} this
23696 * Auto save the htmlEditor value as a file into Events
23697 * @param {HtmlEditor} this
23701 * @event savedpreview
23702 * preview the saved version of htmlEditor
23703 * @param {HtmlEditor} this
23710 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23714 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23719 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23724 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23729 * @cfg {Number} height (in pixels)
23733 * @cfg {Number} width (in pixels)
23738 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23741 stylesheets: false,
23746 // private properties
23747 validationEvent : false,
23749 initialized : false,
23752 onFocus : Roo.emptyFn,
23754 hideMode:'offsets',
23756 tbContainer : false,
23760 toolbarContainer :function() {
23761 return this.wrap.select('.x-html-editor-tb',true).first();
23765 * Protected method that will not generally be called directly. It
23766 * is called when the editor creates its toolbar. Override this method if you need to
23767 * add custom toolbar buttons.
23768 * @param {HtmlEditor} editor
23770 createToolbar : function(){
23771 Roo.log('renewing');
23772 Roo.log("create toolbars");
23774 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23775 this.toolbars[0].render(this.toolbarContainer());
23779 // if (!editor.toolbars || !editor.toolbars.length) {
23780 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23783 // for (var i =0 ; i < editor.toolbars.length;i++) {
23784 // editor.toolbars[i] = Roo.factory(
23785 // typeof(editor.toolbars[i]) == 'string' ?
23786 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23787 // Roo.bootstrap.HtmlEditor);
23788 // editor.toolbars[i].init(editor);
23794 onRender : function(ct, position)
23796 // Roo.log("Call onRender: " + this.xtype);
23798 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23800 this.wrap = this.inputEl().wrap({
23801 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23804 this.editorcore.onRender(ct, position);
23806 if (this.resizable) {
23807 this.resizeEl = new Roo.Resizable(this.wrap, {
23811 minHeight : this.height,
23812 height: this.height,
23813 handles : this.resizable,
23816 resize : function(r, w, h) {
23817 _t.onResize(w,h); // -something
23823 this.createToolbar(this);
23826 if(!this.width && this.resizable){
23827 this.setSize(this.wrap.getSize());
23829 if (this.resizeEl) {
23830 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23831 // should trigger onReize..
23837 onResize : function(w, h)
23839 Roo.log('resize: ' +w + ',' + h );
23840 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23844 if(this.inputEl() ){
23845 if(typeof w == 'number'){
23846 var aw = w - this.wrap.getFrameWidth('lr');
23847 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23850 if(typeof h == 'number'){
23851 var tbh = -11; // fixme it needs to tool bar size!
23852 for (var i =0; i < this.toolbars.length;i++) {
23853 // fixme - ask toolbars for heights?
23854 tbh += this.toolbars[i].el.getHeight();
23855 //if (this.toolbars[i].footer) {
23856 // tbh += this.toolbars[i].footer.el.getHeight();
23864 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23865 ah -= 5; // knock a few pixes off for look..
23866 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23870 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23871 this.editorcore.onResize(ew,eh);
23876 * Toggles the editor between standard and source edit mode.
23877 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23879 toggleSourceEdit : function(sourceEditMode)
23881 this.editorcore.toggleSourceEdit(sourceEditMode);
23883 if(this.editorcore.sourceEditMode){
23884 Roo.log('editor - showing textarea');
23887 // Roo.log(this.syncValue());
23889 this.inputEl().removeClass(['hide', 'x-hidden']);
23890 this.inputEl().dom.removeAttribute('tabIndex');
23891 this.inputEl().focus();
23893 Roo.log('editor - hiding textarea');
23895 // Roo.log(this.pushValue());
23898 this.inputEl().addClass(['hide', 'x-hidden']);
23899 this.inputEl().dom.setAttribute('tabIndex', -1);
23900 //this.deferFocus();
23903 if(this.resizable){
23904 this.setSize(this.wrap.getSize());
23907 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23910 // private (for BoxComponent)
23911 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23913 // private (for BoxComponent)
23914 getResizeEl : function(){
23918 // private (for BoxComponent)
23919 getPositionEl : function(){
23924 initEvents : function(){
23925 this.originalValue = this.getValue();
23929 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23932 // markInvalid : Roo.emptyFn,
23934 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23937 // clearInvalid : Roo.emptyFn,
23939 setValue : function(v){
23940 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23941 this.editorcore.pushValue();
23946 deferFocus : function(){
23947 this.focus.defer(10, this);
23951 focus : function(){
23952 this.editorcore.focus();
23958 onDestroy : function(){
23964 for (var i =0; i < this.toolbars.length;i++) {
23965 // fixme - ask toolbars for heights?
23966 this.toolbars[i].onDestroy();
23969 this.wrap.dom.innerHTML = '';
23970 this.wrap.remove();
23975 onFirstFocus : function(){
23976 //Roo.log("onFirstFocus");
23977 this.editorcore.onFirstFocus();
23978 for (var i =0; i < this.toolbars.length;i++) {
23979 this.toolbars[i].onFirstFocus();
23985 syncValue : function()
23987 this.editorcore.syncValue();
23990 pushValue : function()
23992 this.editorcore.pushValue();
23996 // hide stuff that is not compatible
24010 * @event specialkey
24014 * @cfg {String} fieldClass @hide
24017 * @cfg {String} focusClass @hide
24020 * @cfg {String} autoCreate @hide
24023 * @cfg {String} inputType @hide
24027 * @cfg {String} invalidText @hide
24030 * @cfg {String} msgFx @hide
24033 * @cfg {String} validateOnBlur @hide
24042 Roo.namespace('Roo.bootstrap.htmleditor');
24044 * @class Roo.bootstrap.HtmlEditorToolbar1
24049 new Roo.bootstrap.HtmlEditor({
24052 new Roo.bootstrap.HtmlEditorToolbar1({
24053 disable : { fonts: 1 , format: 1, ..., ... , ...],
24059 * @cfg {Object} disable List of elements to disable..
24060 * @cfg {Array} btns List of additional buttons.
24064 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24067 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24070 Roo.apply(this, config);
24072 // default disabled, based on 'good practice'..
24073 this.disable = this.disable || {};
24074 Roo.applyIf(this.disable, {
24077 specialElements : true
24079 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24081 this.editor = config.editor;
24082 this.editorcore = config.editor.editorcore;
24084 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24086 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24087 // dont call parent... till later.
24089 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24094 editorcore : false,
24099 "h1","h2","h3","h4","h5","h6",
24101 "abbr", "acronym", "address", "cite", "samp", "var",
24105 onRender : function(ct, position)
24107 // Roo.log("Call onRender: " + this.xtype);
24109 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24111 this.el.dom.style.marginBottom = '0';
24113 var editorcore = this.editorcore;
24114 var editor= this.editor;
24117 var btn = function(id,cmd , toggle, handler, html){
24119 var event = toggle ? 'toggle' : 'click';
24124 xns: Roo.bootstrap,
24128 enableToggle:toggle !== false,
24130 pressed : toggle ? false : null,
24133 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24134 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24140 // var cb_box = function...
24145 xns: Roo.bootstrap,
24150 xns: Roo.bootstrap,
24154 Roo.each(this.formats, function(f) {
24155 style.menu.items.push({
24157 xns: Roo.bootstrap,
24158 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24163 editorcore.insertTag(this.tagname);
24170 children.push(style);
24172 btn('bold',false,true);
24173 btn('italic',false,true);
24174 btn('align-left', 'justifyleft',true);
24175 btn('align-center', 'justifycenter',true);
24176 btn('align-right' , 'justifyright',true);
24177 btn('link', false, false, function(btn) {
24178 //Roo.log("create link?");
24179 var url = prompt(this.createLinkText, this.defaultLinkValue);
24180 if(url && url != 'http:/'+'/'){
24181 this.editorcore.relayCmd('createlink', url);
24184 btn('list','insertunorderedlist',true);
24185 btn('pencil', false,true, function(btn){
24187 this.toggleSourceEdit(btn.pressed);
24190 if (this.editor.btns.length > 0) {
24191 for (var i = 0; i<this.editor.btns.length; i++) {
24192 children.push(this.editor.btns[i]);
24200 xns: Roo.bootstrap,
24205 xns: Roo.bootstrap,
24210 cog.menu.items.push({
24212 xns: Roo.bootstrap,
24213 html : Clean styles,
24218 editorcore.insertTag(this.tagname);
24227 this.xtype = 'NavSimplebar';
24229 for(var i=0;i< children.length;i++) {
24231 this.buttons.add(this.addxtypeChild(children[i]));
24235 editor.on('editorevent', this.updateToolbar, this);
24237 onBtnClick : function(id)
24239 this.editorcore.relayCmd(id);
24240 this.editorcore.focus();
24244 * Protected method that will not generally be called directly. It triggers
24245 * a toolbar update by reading the markup state of the current selection in the editor.
24247 updateToolbar: function(){
24249 if(!this.editorcore.activated){
24250 this.editor.onFirstFocus(); // is this neeed?
24254 var btns = this.buttons;
24255 var doc = this.editorcore.doc;
24256 btns.get('bold').setActive(doc.queryCommandState('bold'));
24257 btns.get('italic').setActive(doc.queryCommandState('italic'));
24258 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24260 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24261 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24262 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24264 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24265 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24268 var ans = this.editorcore.getAllAncestors();
24269 if (this.formatCombo) {
24272 var store = this.formatCombo.store;
24273 this.formatCombo.setValue("");
24274 for (var i =0; i < ans.length;i++) {
24275 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24277 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24285 // hides menus... - so this cant be on a menu...
24286 Roo.bootstrap.MenuMgr.hideAll();
24288 Roo.bootstrap.MenuMgr.hideAll();
24289 //this.editorsyncValue();
24291 onFirstFocus: function() {
24292 this.buttons.each(function(item){
24296 toggleSourceEdit : function(sourceEditMode){
24299 if(sourceEditMode){
24300 Roo.log("disabling buttons");
24301 this.buttons.each( function(item){
24302 if(item.cmd != 'pencil'){
24308 Roo.log("enabling buttons");
24309 if(this.editorcore.initialized){
24310 this.buttons.each( function(item){
24316 Roo.log("calling toggole on editor");
24317 // tell the editor that it's been pressed..
24318 this.editor.toggleSourceEdit(sourceEditMode);
24328 * @class Roo.bootstrap.Table.AbstractSelectionModel
24329 * @extends Roo.util.Observable
24330 * Abstract base class for grid SelectionModels. It provides the interface that should be
24331 * implemented by descendant classes. This class should not be directly instantiated.
24334 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24335 this.locked = false;
24336 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24340 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24341 /** @ignore Called by the grid automatically. Do not call directly. */
24342 init : function(grid){
24348 * Locks the selections.
24351 this.locked = true;
24355 * Unlocks the selections.
24357 unlock : function(){
24358 this.locked = false;
24362 * Returns true if the selections are locked.
24363 * @return {Boolean}
24365 isLocked : function(){
24366 return this.locked;
24370 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24371 * @class Roo.bootstrap.Table.RowSelectionModel
24372 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24373 * It supports multiple selections and keyboard selection/navigation.
24375 * @param {Object} config
24378 Roo.bootstrap.Table.RowSelectionModel = function(config){
24379 Roo.apply(this, config);
24380 this.selections = new Roo.util.MixedCollection(false, function(o){
24385 this.lastActive = false;
24389 * @event selectionchange
24390 * Fires when the selection changes
24391 * @param {SelectionModel} this
24393 "selectionchange" : true,
24395 * @event afterselectionchange
24396 * Fires after the selection changes (eg. by key press or clicking)
24397 * @param {SelectionModel} this
24399 "afterselectionchange" : true,
24401 * @event beforerowselect
24402 * Fires when a row is selected being selected, return false to cancel.
24403 * @param {SelectionModel} this
24404 * @param {Number} rowIndex The selected index
24405 * @param {Boolean} keepExisting False if other selections will be cleared
24407 "beforerowselect" : true,
24410 * Fires when a row is selected.
24411 * @param {SelectionModel} this
24412 * @param {Number} rowIndex The selected index
24413 * @param {Roo.data.Record} r The record
24415 "rowselect" : true,
24417 * @event rowdeselect
24418 * Fires when a row is deselected.
24419 * @param {SelectionModel} this
24420 * @param {Number} rowIndex The selected index
24422 "rowdeselect" : true
24424 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24425 this.locked = false;
24428 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24430 * @cfg {Boolean} singleSelect
24431 * True to allow selection of only one row at a time (defaults to false)
24433 singleSelect : false,
24436 initEvents : function()
24439 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24440 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24441 //}else{ // allow click to work like normal
24442 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24444 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24445 this.grid.on("rowclick", this.handleMouseDown, this);
24447 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24448 "up" : function(e){
24450 this.selectPrevious(e.shiftKey);
24451 }else if(this.last !== false && this.lastActive !== false){
24452 var last = this.last;
24453 this.selectRange(this.last, this.lastActive-1);
24454 this.grid.getView().focusRow(this.lastActive);
24455 if(last !== false){
24459 this.selectFirstRow();
24461 this.fireEvent("afterselectionchange", this);
24463 "down" : function(e){
24465 this.selectNext(e.shiftKey);
24466 }else if(this.last !== false && this.lastActive !== false){
24467 var last = this.last;
24468 this.selectRange(this.last, this.lastActive+1);
24469 this.grid.getView().focusRow(this.lastActive);
24470 if(last !== false){
24474 this.selectFirstRow();
24476 this.fireEvent("afterselectionchange", this);
24480 this.grid.store.on('load', function(){
24481 this.selections.clear();
24484 var view = this.grid.view;
24485 view.on("refresh", this.onRefresh, this);
24486 view.on("rowupdated", this.onRowUpdated, this);
24487 view.on("rowremoved", this.onRemove, this);
24492 onRefresh : function()
24494 var ds = this.grid.store, i, v = this.grid.view;
24495 var s = this.selections;
24496 s.each(function(r){
24497 if((i = ds.indexOfId(r.id)) != -1){
24506 onRemove : function(v, index, r){
24507 this.selections.remove(r);
24511 onRowUpdated : function(v, index, r){
24512 if(this.isSelected(r)){
24513 v.onRowSelect(index);
24519 * @param {Array} records The records to select
24520 * @param {Boolean} keepExisting (optional) True to keep existing selections
24522 selectRecords : function(records, keepExisting)
24525 this.clearSelections();
24527 var ds = this.grid.store;
24528 for(var i = 0, len = records.length; i < len; i++){
24529 this.selectRow(ds.indexOf(records[i]), true);
24534 * Gets the number of selected rows.
24537 getCount : function(){
24538 return this.selections.length;
24542 * Selects the first row in the grid.
24544 selectFirstRow : function(){
24549 * Select the last row.
24550 * @param {Boolean} keepExisting (optional) True to keep existing selections
24552 selectLastRow : function(keepExisting){
24553 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24554 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24558 * Selects the row immediately following the last selected row.
24559 * @param {Boolean} keepExisting (optional) True to keep existing selections
24561 selectNext : function(keepExisting)
24563 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24564 this.selectRow(this.last+1, keepExisting);
24565 this.grid.getView().focusRow(this.last);
24570 * Selects the row that precedes the last selected row.
24571 * @param {Boolean} keepExisting (optional) True to keep existing selections
24573 selectPrevious : function(keepExisting){
24575 this.selectRow(this.last-1, keepExisting);
24576 this.grid.getView().focusRow(this.last);
24581 * Returns the selected records
24582 * @return {Array} Array of selected records
24584 getSelections : function(){
24585 return [].concat(this.selections.items);
24589 * Returns the first selected record.
24592 getSelected : function(){
24593 return this.selections.itemAt(0);
24598 * Clears all selections.
24600 clearSelections : function(fast)
24606 var ds = this.grid.store;
24607 var s = this.selections;
24608 s.each(function(r){
24609 this.deselectRow(ds.indexOfId(r.id));
24613 this.selections.clear();
24620 * Selects all rows.
24622 selectAll : function(){
24626 this.selections.clear();
24627 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24628 this.selectRow(i, true);
24633 * Returns True if there is a selection.
24634 * @return {Boolean}
24636 hasSelection : function(){
24637 return this.selections.length > 0;
24641 * Returns True if the specified row is selected.
24642 * @param {Number/Record} record The record or index of the record to check
24643 * @return {Boolean}
24645 isSelected : function(index){
24646 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24647 return (r && this.selections.key(r.id) ? true : false);
24651 * Returns True if the specified record id is selected.
24652 * @param {String} id The id of record to check
24653 * @return {Boolean}
24655 isIdSelected : function(id){
24656 return (this.selections.key(id) ? true : false);
24661 handleMouseDBClick : function(e, t){
24665 handleMouseDown : function(e, t)
24667 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24668 if(this.isLocked() || rowIndex < 0 ){
24671 if(e.shiftKey && this.last !== false){
24672 var last = this.last;
24673 this.selectRange(last, rowIndex, e.ctrlKey);
24674 this.last = last; // reset the last
24678 var isSelected = this.isSelected(rowIndex);
24679 //Roo.log("select row:" + rowIndex);
24681 this.deselectRow(rowIndex);
24683 this.selectRow(rowIndex, true);
24687 if(e.button !== 0 && isSelected){
24688 alert('rowIndex 2: ' + rowIndex);
24689 view.focusRow(rowIndex);
24690 }else if(e.ctrlKey && isSelected){
24691 this.deselectRow(rowIndex);
24692 }else if(!isSelected){
24693 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24694 view.focusRow(rowIndex);
24698 this.fireEvent("afterselectionchange", this);
24701 handleDragableRowClick : function(grid, rowIndex, e)
24703 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24704 this.selectRow(rowIndex, false);
24705 grid.view.focusRow(rowIndex);
24706 this.fireEvent("afterselectionchange", this);
24711 * Selects multiple rows.
24712 * @param {Array} rows Array of the indexes of the row to select
24713 * @param {Boolean} keepExisting (optional) True to keep existing selections
24715 selectRows : function(rows, keepExisting){
24717 this.clearSelections();
24719 for(var i = 0, len = rows.length; i < len; i++){
24720 this.selectRow(rows[i], true);
24725 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24726 * @param {Number} startRow The index of the first row in the range
24727 * @param {Number} endRow The index of the last row in the range
24728 * @param {Boolean} keepExisting (optional) True to retain existing selections
24730 selectRange : function(startRow, endRow, keepExisting){
24735 this.clearSelections();
24737 if(startRow <= endRow){
24738 for(var i = startRow; i <= endRow; i++){
24739 this.selectRow(i, true);
24742 for(var i = startRow; i >= endRow; i--){
24743 this.selectRow(i, true);
24749 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24750 * @param {Number} startRow The index of the first row in the range
24751 * @param {Number} endRow The index of the last row in the range
24753 deselectRange : function(startRow, endRow, preventViewNotify){
24757 for(var i = startRow; i <= endRow; i++){
24758 this.deselectRow(i, preventViewNotify);
24764 * @param {Number} row The index of the row to select
24765 * @param {Boolean} keepExisting (optional) True to keep existing selections
24767 selectRow : function(index, keepExisting, preventViewNotify)
24769 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24772 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24773 if(!keepExisting || this.singleSelect){
24774 this.clearSelections();
24777 var r = this.grid.store.getAt(index);
24778 //console.log('selectRow - record id :' + r.id);
24780 this.selections.add(r);
24781 this.last = this.lastActive = index;
24782 if(!preventViewNotify){
24783 var proxy = new Roo.Element(
24784 this.grid.getRowDom(index)
24786 proxy.addClass('bg-info info');
24788 this.fireEvent("rowselect", this, index, r);
24789 this.fireEvent("selectionchange", this);
24795 * @param {Number} row The index of the row to deselect
24797 deselectRow : function(index, preventViewNotify)
24802 if(this.last == index){
24805 if(this.lastActive == index){
24806 this.lastActive = false;
24809 var r = this.grid.store.getAt(index);
24814 this.selections.remove(r);
24815 //.console.log('deselectRow - record id :' + r.id);
24816 if(!preventViewNotify){
24818 var proxy = new Roo.Element(
24819 this.grid.getRowDom(index)
24821 proxy.removeClass('bg-info info');
24823 this.fireEvent("rowdeselect", this, index);
24824 this.fireEvent("selectionchange", this);
24828 restoreLast : function(){
24830 this.last = this._last;
24835 acceptsNav : function(row, col, cm){
24836 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24840 onEditorKey : function(field, e){
24841 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24846 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24848 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24850 }else if(k == e.ENTER && !e.ctrlKey){
24854 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24856 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24858 }else if(k == e.ESC){
24862 g.startEditing(newCell[0], newCell[1]);
24868 * Ext JS Library 1.1.1
24869 * Copyright(c) 2006-2007, Ext JS, LLC.
24871 * Originally Released Under LGPL - original licence link has changed is not relivant.
24874 * <script type="text/javascript">
24878 * @class Roo.bootstrap.PagingToolbar
24879 * @extends Roo.bootstrap.NavSimplebar
24880 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24882 * Create a new PagingToolbar
24883 * @param {Object} config The config object
24884 * @param {Roo.data.Store} store
24886 Roo.bootstrap.PagingToolbar = function(config)
24888 // old args format still supported... - xtype is prefered..
24889 // created from xtype...
24891 this.ds = config.dataSource;
24893 if (config.store && !this.ds) {
24894 this.store= Roo.factory(config.store, Roo.data);
24895 this.ds = this.store;
24896 this.ds.xmodule = this.xmodule || false;
24899 this.toolbarItems = [];
24900 if (config.items) {
24901 this.toolbarItems = config.items;
24904 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24909 this.bind(this.ds);
24912 if (Roo.bootstrap.version == 4) {
24913 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24915 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24920 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24922 * @cfg {Roo.data.Store} dataSource
24923 * The underlying data store providing the paged data
24926 * @cfg {String/HTMLElement/Element} container
24927 * container The id or element that will contain the toolbar
24930 * @cfg {Boolean} displayInfo
24931 * True to display the displayMsg (defaults to false)
24934 * @cfg {Number} pageSize
24935 * The number of records to display per page (defaults to 20)
24939 * @cfg {String} displayMsg
24940 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24942 displayMsg : 'Displaying {0} - {1} of {2}',
24944 * @cfg {String} emptyMsg
24945 * The message to display when no records are found (defaults to "No data to display")
24947 emptyMsg : 'No data to display',
24949 * Customizable piece of the default paging text (defaults to "Page")
24952 beforePageText : "Page",
24954 * Customizable piece of the default paging text (defaults to "of %0")
24957 afterPageText : "of {0}",
24959 * Customizable piece of the default paging text (defaults to "First Page")
24962 firstText : "First Page",
24964 * Customizable piece of the default paging text (defaults to "Previous Page")
24967 prevText : "Previous Page",
24969 * Customizable piece of the default paging text (defaults to "Next Page")
24972 nextText : "Next Page",
24974 * Customizable piece of the default paging text (defaults to "Last Page")
24977 lastText : "Last Page",
24979 * Customizable piece of the default paging text (defaults to "Refresh")
24982 refreshText : "Refresh",
24986 onRender : function(ct, position)
24988 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24989 this.navgroup.parentId = this.id;
24990 this.navgroup.onRender(this.el, null);
24991 // add the buttons to the navgroup
24993 if(this.displayInfo){
24994 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24995 this.displayEl = this.el.select('.x-paging-info', true).first();
24996 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24997 // this.displayEl = navel.el.select('span',true).first();
25003 Roo.each(_this.buttons, function(e){ // this might need to use render????
25004 Roo.factory(e).render(_this.el);
25008 Roo.each(_this.toolbarItems, function(e) {
25009 _this.navgroup.addItem(e);
25013 this.first = this.navgroup.addItem({
25014 tooltip: this.firstText,
25015 cls: "prev btn-outline-secondary",
25016 html : ' <i class="fa fa-step-backward"></i>',
25018 preventDefault: true,
25019 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25022 this.prev = this.navgroup.addItem({
25023 tooltip: this.prevText,
25024 cls: "prev btn-outline-secondary",
25025 html : ' <i class="fa fa-backward"></i>',
25027 preventDefault: true,
25028 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25030 //this.addSeparator();
25033 var field = this.navgroup.addItem( {
25035 cls : 'x-paging-position btn-outline-secondary',
25037 html : this.beforePageText +
25038 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25039 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25042 this.field = field.el.select('input', true).first();
25043 this.field.on("keydown", this.onPagingKeydown, this);
25044 this.field.on("focus", function(){this.dom.select();});
25047 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25048 //this.field.setHeight(18);
25049 //this.addSeparator();
25050 this.next = this.navgroup.addItem({
25051 tooltip: this.nextText,
25052 cls: "next btn-outline-secondary",
25053 html : ' <i class="fa fa-forward"></i>',
25055 preventDefault: true,
25056 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25058 this.last = this.navgroup.addItem({
25059 tooltip: this.lastText,
25060 html : ' <i class="fa fa-step-forward"></i>',
25061 cls: "next btn-outline-secondary",
25063 preventDefault: true,
25064 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25066 //this.addSeparator();
25067 this.loading = this.navgroup.addItem({
25068 tooltip: this.refreshText,
25069 cls: "btn-outline-secondary",
25070 html : ' <i class="fa fa-refresh"></i>',
25071 preventDefault: true,
25072 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25078 updateInfo : function(){
25079 if(this.displayEl){
25080 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25081 var msg = count == 0 ?
25085 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25087 this.displayEl.update(msg);
25092 onLoad : function(ds, r, o)
25094 this.cursor = o.params.start ? o.params.start : 0;
25096 var d = this.getPageData(),
25101 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25102 this.field.dom.value = ap;
25103 this.first.setDisabled(ap == 1);
25104 this.prev.setDisabled(ap == 1);
25105 this.next.setDisabled(ap == ps);
25106 this.last.setDisabled(ap == ps);
25107 this.loading.enable();
25112 getPageData : function(){
25113 var total = this.ds.getTotalCount();
25116 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25117 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25122 onLoadError : function(){
25123 this.loading.enable();
25127 onPagingKeydown : function(e){
25128 var k = e.getKey();
25129 var d = this.getPageData();
25131 var v = this.field.dom.value, pageNum;
25132 if(!v || isNaN(pageNum = parseInt(v, 10))){
25133 this.field.dom.value = d.activePage;
25136 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25137 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25140 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))
25142 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25143 this.field.dom.value = pageNum;
25144 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25147 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25149 var v = this.field.dom.value, pageNum;
25150 var increment = (e.shiftKey) ? 10 : 1;
25151 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25154 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25155 this.field.dom.value = d.activePage;
25158 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25160 this.field.dom.value = parseInt(v, 10) + increment;
25161 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25162 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25169 beforeLoad : function(){
25171 this.loading.disable();
25176 onClick : function(which){
25185 ds.load({params:{start: 0, limit: this.pageSize}});
25188 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25191 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25194 var total = ds.getTotalCount();
25195 var extra = total % this.pageSize;
25196 var lastStart = extra ? (total - extra) : total-this.pageSize;
25197 ds.load({params:{start: lastStart, limit: this.pageSize}});
25200 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25206 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25207 * @param {Roo.data.Store} store The data store to unbind
25209 unbind : function(ds){
25210 ds.un("beforeload", this.beforeLoad, this);
25211 ds.un("load", this.onLoad, this);
25212 ds.un("loadexception", this.onLoadError, this);
25213 ds.un("remove", this.updateInfo, this);
25214 ds.un("add", this.updateInfo, this);
25215 this.ds = undefined;
25219 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25220 * @param {Roo.data.Store} store The data store to bind
25222 bind : function(ds){
25223 ds.on("beforeload", this.beforeLoad, this);
25224 ds.on("load", this.onLoad, this);
25225 ds.on("loadexception", this.onLoadError, this);
25226 ds.on("remove", this.updateInfo, this);
25227 ds.on("add", this.updateInfo, this);
25238 * @class Roo.bootstrap.MessageBar
25239 * @extends Roo.bootstrap.Component
25240 * Bootstrap MessageBar class
25241 * @cfg {String} html contents of the MessageBar
25242 * @cfg {String} weight (info | success | warning | danger) default info
25243 * @cfg {String} beforeClass insert the bar before the given class
25244 * @cfg {Boolean} closable (true | false) default false
25245 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25248 * Create a new Element
25249 * @param {Object} config The config object
25252 Roo.bootstrap.MessageBar = function(config){
25253 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25256 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25262 beforeClass: 'bootstrap-sticky-wrap',
25264 getAutoCreate : function(){
25268 cls: 'alert alert-dismissable alert-' + this.weight,
25273 html: this.html || ''
25279 cfg.cls += ' alert-messages-fixed';
25293 onRender : function(ct, position)
25295 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25298 var cfg = Roo.apply({}, this.getAutoCreate());
25302 cfg.cls += ' ' + this.cls;
25305 cfg.style = this.style;
25307 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25309 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25312 this.el.select('>button.close').on('click', this.hide, this);
25318 if (!this.rendered) {
25324 this.fireEvent('show', this);
25330 if (!this.rendered) {
25336 this.fireEvent('hide', this);
25339 update : function()
25341 // var e = this.el.dom.firstChild;
25343 // if(this.closable){
25344 // e = e.nextSibling;
25347 // e.data = this.html || '';
25349 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25365 * @class Roo.bootstrap.Graph
25366 * @extends Roo.bootstrap.Component
25367 * Bootstrap Graph class
25371 @cfg {String} graphtype bar | vbar | pie
25372 @cfg {number} g_x coodinator | centre x (pie)
25373 @cfg {number} g_y coodinator | centre y (pie)
25374 @cfg {number} g_r radius (pie)
25375 @cfg {number} g_height height of the chart (respected by all elements in the set)
25376 @cfg {number} g_width width of the chart (respected by all elements in the set)
25377 @cfg {Object} title The title of the chart
25380 -opts (object) options for the chart
25382 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25383 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25385 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.
25386 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25388 o stretch (boolean)
25390 -opts (object) options for the pie
25393 o startAngle (number)
25394 o endAngle (number)
25398 * Create a new Input
25399 * @param {Object} config The config object
25402 Roo.bootstrap.Graph = function(config){
25403 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25409 * The img click event for the img.
25410 * @param {Roo.EventObject} e
25416 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25427 //g_colors: this.colors,
25434 getAutoCreate : function(){
25445 onRender : function(ct,position){
25448 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25450 if (typeof(Raphael) == 'undefined') {
25451 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25455 this.raphael = Raphael(this.el.dom);
25457 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25458 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25459 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25460 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25462 r.text(160, 10, "Single Series Chart").attr(txtattr);
25463 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25464 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25465 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25467 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25468 r.barchart(330, 10, 300, 220, data1);
25469 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25470 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25473 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25474 // r.barchart(30, 30, 560, 250, xdata, {
25475 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25476 // axis : "0 0 1 1",
25477 // axisxlabels : xdata
25478 // //yvalues : cols,
25481 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25483 // this.load(null,xdata,{
25484 // axis : "0 0 1 1",
25485 // axisxlabels : xdata
25490 load : function(graphtype,xdata,opts)
25492 this.raphael.clear();
25494 graphtype = this.graphtype;
25499 var r = this.raphael,
25500 fin = function () {
25501 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25503 fout = function () {
25504 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25506 pfin = function() {
25507 this.sector.stop();
25508 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25511 this.label[0].stop();
25512 this.label[0].attr({ r: 7.5 });
25513 this.label[1].attr({ "font-weight": 800 });
25516 pfout = function() {
25517 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25520 this.label[0].animate({ r: 5 }, 500, "bounce");
25521 this.label[1].attr({ "font-weight": 400 });
25527 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25530 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25533 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25534 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25536 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25543 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25548 setTitle: function(o)
25553 initEvents: function() {
25556 this.el.on('click', this.onClick, this);
25560 onClick : function(e)
25562 Roo.log('img onclick');
25563 this.fireEvent('click', this, e);
25575 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25578 * @class Roo.bootstrap.dash.NumberBox
25579 * @extends Roo.bootstrap.Component
25580 * Bootstrap NumberBox class
25581 * @cfg {String} headline Box headline
25582 * @cfg {String} content Box content
25583 * @cfg {String} icon Box icon
25584 * @cfg {String} footer Footer text
25585 * @cfg {String} fhref Footer href
25588 * Create a new NumberBox
25589 * @param {Object} config The config object
25593 Roo.bootstrap.dash.NumberBox = function(config){
25594 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25598 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25607 getAutoCreate : function(){
25611 cls : 'small-box ',
25619 cls : 'roo-headline',
25620 html : this.headline
25624 cls : 'roo-content',
25625 html : this.content
25639 cls : 'ion ' + this.icon
25648 cls : 'small-box-footer',
25649 href : this.fhref || '#',
25653 cfg.cn.push(footer);
25660 onRender : function(ct,position){
25661 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25668 setHeadline: function (value)
25670 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25673 setFooter: function (value, href)
25675 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25678 this.el.select('a.small-box-footer',true).first().attr('href', href);
25683 setContent: function (value)
25685 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25688 initEvents: function()
25702 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25705 * @class Roo.bootstrap.dash.TabBox
25706 * @extends Roo.bootstrap.Component
25707 * Bootstrap TabBox class
25708 * @cfg {String} title Title of the TabBox
25709 * @cfg {String} icon Icon of the TabBox
25710 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25711 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25714 * Create a new TabBox
25715 * @param {Object} config The config object
25719 Roo.bootstrap.dash.TabBox = function(config){
25720 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25725 * When a pane is added
25726 * @param {Roo.bootstrap.dash.TabPane} pane
25730 * @event activatepane
25731 * When a pane is activated
25732 * @param {Roo.bootstrap.dash.TabPane} pane
25734 "activatepane" : true
25742 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25747 tabScrollable : false,
25749 getChildContainer : function()
25751 return this.el.select('.tab-content', true).first();
25754 getAutoCreate : function(){
25758 cls: 'pull-left header',
25766 cls: 'fa ' + this.icon
25772 cls: 'nav nav-tabs pull-right',
25778 if(this.tabScrollable){
25785 cls: 'nav nav-tabs pull-right',
25796 cls: 'nav-tabs-custom',
25801 cls: 'tab-content no-padding',
25809 initEvents : function()
25811 //Roo.log('add add pane handler');
25812 this.on('addpane', this.onAddPane, this);
25815 * Updates the box title
25816 * @param {String} html to set the title to.
25818 setTitle : function(value)
25820 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25822 onAddPane : function(pane)
25824 this.panes.push(pane);
25825 //Roo.log('addpane');
25827 // tabs are rendere left to right..
25828 if(!this.showtabs){
25832 var ctr = this.el.select('.nav-tabs', true).first();
25835 var existing = ctr.select('.nav-tab',true);
25836 var qty = existing.getCount();;
25839 var tab = ctr.createChild({
25841 cls : 'nav-tab' + (qty ? '' : ' active'),
25849 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25852 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25854 pane.el.addClass('active');
25859 onTabClick : function(ev,un,ob,pane)
25861 //Roo.log('tab - prev default');
25862 ev.preventDefault();
25865 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25866 pane.tab.addClass('active');
25867 //Roo.log(pane.title);
25868 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25869 // technically we should have a deactivate event.. but maybe add later.
25870 // and it should not de-activate the selected tab...
25871 this.fireEvent('activatepane', pane);
25872 pane.el.addClass('active');
25873 pane.fireEvent('activate');
25878 getActivePane : function()
25881 Roo.each(this.panes, function(p) {
25882 if(p.el.hasClass('active')){
25903 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25905 * @class Roo.bootstrap.TabPane
25906 * @extends Roo.bootstrap.Component
25907 * Bootstrap TabPane class
25908 * @cfg {Boolean} active (false | true) Default false
25909 * @cfg {String} title title of panel
25913 * Create a new TabPane
25914 * @param {Object} config The config object
25917 Roo.bootstrap.dash.TabPane = function(config){
25918 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25924 * When a pane is activated
25925 * @param {Roo.bootstrap.dash.TabPane} pane
25932 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25937 // the tabBox that this is attached to.
25940 getAutoCreate : function()
25948 cfg.cls += ' active';
25953 initEvents : function()
25955 //Roo.log('trigger add pane handler');
25956 this.parent().fireEvent('addpane', this)
25960 * Updates the tab title
25961 * @param {String} html to set the title to.
25963 setTitle: function(str)
25969 this.tab.select('a', true).first().dom.innerHTML = str;
25986 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25989 * @class Roo.bootstrap.menu.Menu
25990 * @extends Roo.bootstrap.Component
25991 * Bootstrap Menu class - container for Menu
25992 * @cfg {String} html Text of the menu
25993 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25994 * @cfg {String} icon Font awesome icon
25995 * @cfg {String} pos Menu align to (top | bottom) default bottom
25999 * Create a new Menu
26000 * @param {Object} config The config object
26004 Roo.bootstrap.menu.Menu = function(config){
26005 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26009 * @event beforeshow
26010 * Fires before this menu is displayed
26011 * @param {Roo.bootstrap.menu.Menu} this
26015 * @event beforehide
26016 * Fires before this menu is hidden
26017 * @param {Roo.bootstrap.menu.Menu} this
26022 * Fires after this menu is displayed
26023 * @param {Roo.bootstrap.menu.Menu} this
26028 * Fires after this menu is hidden
26029 * @param {Roo.bootstrap.menu.Menu} this
26034 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26035 * @param {Roo.bootstrap.menu.Menu} this
26036 * @param {Roo.EventObject} e
26043 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26047 weight : 'default',
26052 getChildContainer : function() {
26053 if(this.isSubMenu){
26057 return this.el.select('ul.dropdown-menu', true).first();
26060 getAutoCreate : function()
26065 cls : 'roo-menu-text',
26073 cls : 'fa ' + this.icon
26084 cls : 'dropdown-button btn btn-' + this.weight,
26089 cls : 'dropdown-toggle btn btn-' + this.weight,
26099 cls : 'dropdown-menu'
26105 if(this.pos == 'top'){
26106 cfg.cls += ' dropup';
26109 if(this.isSubMenu){
26112 cls : 'dropdown-menu'
26119 onRender : function(ct, position)
26121 this.isSubMenu = ct.hasClass('dropdown-submenu');
26123 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26126 initEvents : function()
26128 if(this.isSubMenu){
26132 this.hidden = true;
26134 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26135 this.triggerEl.on('click', this.onTriggerPress, this);
26137 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26138 this.buttonEl.on('click', this.onClick, this);
26144 if(this.isSubMenu){
26148 return this.el.select('ul.dropdown-menu', true).first();
26151 onClick : function(e)
26153 this.fireEvent("click", this, e);
26156 onTriggerPress : function(e)
26158 if (this.isVisible()) {
26165 isVisible : function(){
26166 return !this.hidden;
26171 this.fireEvent("beforeshow", this);
26173 this.hidden = false;
26174 this.el.addClass('open');
26176 Roo.get(document).on("mouseup", this.onMouseUp, this);
26178 this.fireEvent("show", this);
26185 this.fireEvent("beforehide", this);
26187 this.hidden = true;
26188 this.el.removeClass('open');
26190 Roo.get(document).un("mouseup", this.onMouseUp);
26192 this.fireEvent("hide", this);
26195 onMouseUp : function()
26209 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26212 * @class Roo.bootstrap.menu.Item
26213 * @extends Roo.bootstrap.Component
26214 * Bootstrap MenuItem class
26215 * @cfg {Boolean} submenu (true | false) default false
26216 * @cfg {String} html text of the item
26217 * @cfg {String} href the link
26218 * @cfg {Boolean} disable (true | false) default false
26219 * @cfg {Boolean} preventDefault (true | false) default true
26220 * @cfg {String} icon Font awesome icon
26221 * @cfg {String} pos Submenu align to (left | right) default right
26225 * Create a new Item
26226 * @param {Object} config The config object
26230 Roo.bootstrap.menu.Item = function(config){
26231 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26235 * Fires when the mouse is hovering over this menu
26236 * @param {Roo.bootstrap.menu.Item} this
26237 * @param {Roo.EventObject} e
26242 * Fires when the mouse exits this menu
26243 * @param {Roo.bootstrap.menu.Item} this
26244 * @param {Roo.EventObject} e
26250 * The raw click event for the entire grid.
26251 * @param {Roo.EventObject} e
26257 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26262 preventDefault: true,
26267 getAutoCreate : function()
26272 cls : 'roo-menu-item-text',
26280 cls : 'fa ' + this.icon
26289 href : this.href || '#',
26296 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26300 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26302 if(this.pos == 'left'){
26303 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26310 initEvents : function()
26312 this.el.on('mouseover', this.onMouseOver, this);
26313 this.el.on('mouseout', this.onMouseOut, this);
26315 this.el.select('a', true).first().on('click', this.onClick, this);
26319 onClick : function(e)
26321 if(this.preventDefault){
26322 e.preventDefault();
26325 this.fireEvent("click", this, e);
26328 onMouseOver : function(e)
26330 if(this.submenu && this.pos == 'left'){
26331 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26334 this.fireEvent("mouseover", this, e);
26337 onMouseOut : function(e)
26339 this.fireEvent("mouseout", this, e);
26351 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26354 * @class Roo.bootstrap.menu.Separator
26355 * @extends Roo.bootstrap.Component
26356 * Bootstrap Separator class
26359 * Create a new Separator
26360 * @param {Object} config The config object
26364 Roo.bootstrap.menu.Separator = function(config){
26365 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26368 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26370 getAutoCreate : function(){
26391 * @class Roo.bootstrap.Tooltip
26392 * Bootstrap Tooltip class
26393 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26394 * to determine which dom element triggers the tooltip.
26396 * It needs to add support for additional attributes like tooltip-position
26399 * Create a new Toolti
26400 * @param {Object} config The config object
26403 Roo.bootstrap.Tooltip = function(config){
26404 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26406 this.alignment = Roo.bootstrap.Tooltip.alignment;
26408 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26409 this.alignment = config.alignment;
26414 Roo.apply(Roo.bootstrap.Tooltip, {
26416 * @function init initialize tooltip monitoring.
26420 currentTip : false,
26421 currentRegion : false,
26427 Roo.get(document).on('mouseover', this.enter ,this);
26428 Roo.get(document).on('mouseout', this.leave, this);
26431 this.currentTip = new Roo.bootstrap.Tooltip();
26434 enter : function(ev)
26436 var dom = ev.getTarget();
26438 //Roo.log(['enter',dom]);
26439 var el = Roo.fly(dom);
26440 if (this.currentEl) {
26442 //Roo.log(this.currentEl);
26443 //Roo.log(this.currentEl.contains(dom));
26444 if (this.currentEl == el) {
26447 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26453 if (this.currentTip.el) {
26454 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26458 if(!el || el.dom == document){
26464 // you can not look for children, as if el is the body.. then everythign is the child..
26465 if (!el.attr('tooltip')) { //
26466 if (!el.select("[tooltip]").elements.length) {
26469 // is the mouse over this child...?
26470 bindEl = el.select("[tooltip]").first();
26471 var xy = ev.getXY();
26472 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26473 //Roo.log("not in region.");
26476 //Roo.log("child element over..");
26479 this.currentEl = bindEl;
26480 this.currentTip.bind(bindEl);
26481 this.currentRegion = Roo.lib.Region.getRegion(dom);
26482 this.currentTip.enter();
26485 leave : function(ev)
26487 var dom = ev.getTarget();
26488 //Roo.log(['leave',dom]);
26489 if (!this.currentEl) {
26494 if (dom != this.currentEl.dom) {
26497 var xy = ev.getXY();
26498 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26501 // only activate leave if mouse cursor is outside... bounding box..
26506 if (this.currentTip) {
26507 this.currentTip.leave();
26509 //Roo.log('clear currentEl');
26510 this.currentEl = false;
26515 'left' : ['r-l', [-2,0], 'right'],
26516 'right' : ['l-r', [2,0], 'left'],
26517 'bottom' : ['t-b', [0,2], 'top'],
26518 'top' : [ 'b-t', [0,-2], 'bottom']
26524 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26529 delay : null, // can be { show : 300 , hide: 500}
26533 hoverState : null, //???
26535 placement : 'bottom',
26539 getAutoCreate : function(){
26546 cls : 'tooltip-arrow'
26549 cls : 'tooltip-inner'
26556 bind : function(el)
26562 enter : function () {
26564 if (this.timeout != null) {
26565 clearTimeout(this.timeout);
26568 this.hoverState = 'in';
26569 //Roo.log("enter - show");
26570 if (!this.delay || !this.delay.show) {
26575 this.timeout = setTimeout(function () {
26576 if (_t.hoverState == 'in') {
26579 }, this.delay.show);
26583 clearTimeout(this.timeout);
26585 this.hoverState = 'out';
26586 if (!this.delay || !this.delay.hide) {
26592 this.timeout = setTimeout(function () {
26593 //Roo.log("leave - timeout");
26595 if (_t.hoverState == 'out') {
26597 Roo.bootstrap.Tooltip.currentEl = false;
26602 show : function (msg)
26605 this.render(document.body);
26608 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26610 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26612 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26614 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26616 var placement = typeof this.placement == 'function' ?
26617 this.placement.call(this, this.el, on_el) :
26620 var autoToken = /\s?auto?\s?/i;
26621 var autoPlace = autoToken.test(placement);
26623 placement = placement.replace(autoToken, '') || 'top';
26627 //this.el.setXY([0,0]);
26629 //this.el.dom.style.display='block';
26631 //this.el.appendTo(on_el);
26633 var p = this.getPosition();
26634 var box = this.el.getBox();
26640 var align = this.alignment[placement];
26642 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26644 if(placement == 'top' || placement == 'bottom'){
26646 placement = 'right';
26649 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26650 placement = 'left';
26653 var scroll = Roo.select('body', true).first().getScroll();
26655 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26659 align = this.alignment[placement];
26662 this.el.alignTo(this.bindEl, align[0],align[1]);
26663 //var arrow = this.el.select('.arrow',true).first();
26664 //arrow.set(align[2],
26666 this.el.addClass(placement);
26668 this.el.addClass('in fade');
26670 this.hoverState = null;
26672 if (this.el.hasClass('fade')) {
26683 //this.el.setXY([0,0]);
26684 this.el.removeClass('in');
26700 * @class Roo.bootstrap.LocationPicker
26701 * @extends Roo.bootstrap.Component
26702 * Bootstrap LocationPicker class
26703 * @cfg {Number} latitude Position when init default 0
26704 * @cfg {Number} longitude Position when init default 0
26705 * @cfg {Number} zoom default 15
26706 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26707 * @cfg {Boolean} mapTypeControl default false
26708 * @cfg {Boolean} disableDoubleClickZoom default false
26709 * @cfg {Boolean} scrollwheel default true
26710 * @cfg {Boolean} streetViewControl default false
26711 * @cfg {Number} radius default 0
26712 * @cfg {String} locationName
26713 * @cfg {Boolean} draggable default true
26714 * @cfg {Boolean} enableAutocomplete default false
26715 * @cfg {Boolean} enableReverseGeocode default true
26716 * @cfg {String} markerTitle
26719 * Create a new LocationPicker
26720 * @param {Object} config The config object
26724 Roo.bootstrap.LocationPicker = function(config){
26726 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26731 * Fires when the picker initialized.
26732 * @param {Roo.bootstrap.LocationPicker} this
26733 * @param {Google Location} location
26737 * @event positionchanged
26738 * Fires when the picker position changed.
26739 * @param {Roo.bootstrap.LocationPicker} this
26740 * @param {Google Location} location
26742 positionchanged : true,
26745 * Fires when the map resize.
26746 * @param {Roo.bootstrap.LocationPicker} this
26751 * Fires when the map show.
26752 * @param {Roo.bootstrap.LocationPicker} this
26757 * Fires when the map hide.
26758 * @param {Roo.bootstrap.LocationPicker} this
26763 * Fires when click the map.
26764 * @param {Roo.bootstrap.LocationPicker} this
26765 * @param {Map event} e
26769 * @event mapRightClick
26770 * Fires when right click the map.
26771 * @param {Roo.bootstrap.LocationPicker} this
26772 * @param {Map event} e
26774 mapRightClick : true,
26776 * @event markerClick
26777 * Fires when click the marker.
26778 * @param {Roo.bootstrap.LocationPicker} this
26779 * @param {Map event} e
26781 markerClick : true,
26783 * @event markerRightClick
26784 * Fires when right click the marker.
26785 * @param {Roo.bootstrap.LocationPicker} this
26786 * @param {Map event} e
26788 markerRightClick : true,
26790 * @event OverlayViewDraw
26791 * Fires when OverlayView Draw
26792 * @param {Roo.bootstrap.LocationPicker} this
26794 OverlayViewDraw : true,
26796 * @event OverlayViewOnAdd
26797 * Fires when OverlayView Draw
26798 * @param {Roo.bootstrap.LocationPicker} this
26800 OverlayViewOnAdd : true,
26802 * @event OverlayViewOnRemove
26803 * Fires when OverlayView Draw
26804 * @param {Roo.bootstrap.LocationPicker} this
26806 OverlayViewOnRemove : true,
26808 * @event OverlayViewShow
26809 * Fires when OverlayView Draw
26810 * @param {Roo.bootstrap.LocationPicker} this
26811 * @param {Pixel} cpx
26813 OverlayViewShow : true,
26815 * @event OverlayViewHide
26816 * Fires when OverlayView Draw
26817 * @param {Roo.bootstrap.LocationPicker} this
26819 OverlayViewHide : true,
26821 * @event loadexception
26822 * Fires when load google lib failed.
26823 * @param {Roo.bootstrap.LocationPicker} this
26825 loadexception : true
26830 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26832 gMapContext: false,
26838 mapTypeControl: false,
26839 disableDoubleClickZoom: false,
26841 streetViewControl: false,
26845 enableAutocomplete: false,
26846 enableReverseGeocode: true,
26849 getAutoCreate: function()
26854 cls: 'roo-location-picker'
26860 initEvents: function(ct, position)
26862 if(!this.el.getWidth() || this.isApplied()){
26866 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26871 initial: function()
26873 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26874 this.fireEvent('loadexception', this);
26878 if(!this.mapTypeId){
26879 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26882 this.gMapContext = this.GMapContext();
26884 this.initOverlayView();
26886 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26890 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26891 _this.setPosition(_this.gMapContext.marker.position);
26894 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26895 _this.fireEvent('mapClick', this, event);
26899 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26900 _this.fireEvent('mapRightClick', this, event);
26904 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26905 _this.fireEvent('markerClick', this, event);
26909 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26910 _this.fireEvent('markerRightClick', this, event);
26914 this.setPosition(this.gMapContext.location);
26916 this.fireEvent('initial', this, this.gMapContext.location);
26919 initOverlayView: function()
26923 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26927 _this.fireEvent('OverlayViewDraw', _this);
26932 _this.fireEvent('OverlayViewOnAdd', _this);
26935 onRemove: function()
26937 _this.fireEvent('OverlayViewOnRemove', _this);
26940 show: function(cpx)
26942 _this.fireEvent('OverlayViewShow', _this, cpx);
26947 _this.fireEvent('OverlayViewHide', _this);
26953 fromLatLngToContainerPixel: function(event)
26955 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26958 isApplied: function()
26960 return this.getGmapContext() == false ? false : true;
26963 getGmapContext: function()
26965 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26968 GMapContext: function()
26970 var position = new google.maps.LatLng(this.latitude, this.longitude);
26972 var _map = new google.maps.Map(this.el.dom, {
26975 mapTypeId: this.mapTypeId,
26976 mapTypeControl: this.mapTypeControl,
26977 disableDoubleClickZoom: this.disableDoubleClickZoom,
26978 scrollwheel: this.scrollwheel,
26979 streetViewControl: this.streetViewControl,
26980 locationName: this.locationName,
26981 draggable: this.draggable,
26982 enableAutocomplete: this.enableAutocomplete,
26983 enableReverseGeocode: this.enableReverseGeocode
26986 var _marker = new google.maps.Marker({
26987 position: position,
26989 title: this.markerTitle,
26990 draggable: this.draggable
26997 location: position,
26998 radius: this.radius,
26999 locationName: this.locationName,
27000 addressComponents: {
27001 formatted_address: null,
27002 addressLine1: null,
27003 addressLine2: null,
27005 streetNumber: null,
27009 stateOrProvince: null
27012 domContainer: this.el.dom,
27013 geodecoder: new google.maps.Geocoder()
27017 drawCircle: function(center, radius, options)
27019 if (this.gMapContext.circle != null) {
27020 this.gMapContext.circle.setMap(null);
27024 options = Roo.apply({}, options, {
27025 strokeColor: "#0000FF",
27026 strokeOpacity: .35,
27028 fillColor: "#0000FF",
27032 options.map = this.gMapContext.map;
27033 options.radius = radius;
27034 options.center = center;
27035 this.gMapContext.circle = new google.maps.Circle(options);
27036 return this.gMapContext.circle;
27042 setPosition: function(location)
27044 this.gMapContext.location = location;
27045 this.gMapContext.marker.setPosition(location);
27046 this.gMapContext.map.panTo(location);
27047 this.drawCircle(location, this.gMapContext.radius, {});
27051 if (this.gMapContext.settings.enableReverseGeocode) {
27052 this.gMapContext.geodecoder.geocode({
27053 latLng: this.gMapContext.location
27054 }, function(results, status) {
27056 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27057 _this.gMapContext.locationName = results[0].formatted_address;
27058 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27060 _this.fireEvent('positionchanged', this, location);
27067 this.fireEvent('positionchanged', this, location);
27072 google.maps.event.trigger(this.gMapContext.map, "resize");
27074 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27076 this.fireEvent('resize', this);
27079 setPositionByLatLng: function(latitude, longitude)
27081 this.setPosition(new google.maps.LatLng(latitude, longitude));
27084 getCurrentPosition: function()
27087 latitude: this.gMapContext.location.lat(),
27088 longitude: this.gMapContext.location.lng()
27092 getAddressName: function()
27094 return this.gMapContext.locationName;
27097 getAddressComponents: function()
27099 return this.gMapContext.addressComponents;
27102 address_component_from_google_geocode: function(address_components)
27106 for (var i = 0; i < address_components.length; i++) {
27107 var component = address_components[i];
27108 if (component.types.indexOf("postal_code") >= 0) {
27109 result.postalCode = component.short_name;
27110 } else if (component.types.indexOf("street_number") >= 0) {
27111 result.streetNumber = component.short_name;
27112 } else if (component.types.indexOf("route") >= 0) {
27113 result.streetName = component.short_name;
27114 } else if (component.types.indexOf("neighborhood") >= 0) {
27115 result.city = component.short_name;
27116 } else if (component.types.indexOf("locality") >= 0) {
27117 result.city = component.short_name;
27118 } else if (component.types.indexOf("sublocality") >= 0) {
27119 result.district = component.short_name;
27120 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27121 result.stateOrProvince = component.short_name;
27122 } else if (component.types.indexOf("country") >= 0) {
27123 result.country = component.short_name;
27127 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27128 result.addressLine2 = "";
27132 setZoomLevel: function(zoom)
27134 this.gMapContext.map.setZoom(zoom);
27147 this.fireEvent('show', this);
27158 this.fireEvent('hide', this);
27163 Roo.apply(Roo.bootstrap.LocationPicker, {
27165 OverlayView : function(map, options)
27167 options = options || {};
27181 * @class Roo.bootstrap.Alert
27182 * @extends Roo.bootstrap.Component
27183 * Bootstrap Alert class
27184 * @cfg {String} title The title of alert
27185 * @cfg {String} html The content of alert
27186 * @cfg {String} weight ( success | info | warning | danger )
27187 * @cfg {String} faicon font-awesomeicon
27190 * Create a new alert
27191 * @param {Object} config The config object
27195 Roo.bootstrap.Alert = function(config){
27196 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27200 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27207 getAutoCreate : function()
27216 cls : 'roo-alert-icon'
27221 cls : 'roo-alert-title',
27226 cls : 'roo-alert-text',
27233 cfg.cn[0].cls += ' fa ' + this.faicon;
27237 cfg.cls += ' alert-' + this.weight;
27243 initEvents: function()
27245 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27248 setTitle : function(str)
27250 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27253 setText : function(str)
27255 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27258 setWeight : function(weight)
27261 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27264 this.weight = weight;
27266 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27269 setIcon : function(icon)
27272 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27275 this.faicon = icon;
27277 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27298 * @class Roo.bootstrap.UploadCropbox
27299 * @extends Roo.bootstrap.Component
27300 * Bootstrap UploadCropbox class
27301 * @cfg {String} emptyText show when image has been loaded
27302 * @cfg {String} rotateNotify show when image too small to rotate
27303 * @cfg {Number} errorTimeout default 3000
27304 * @cfg {Number} minWidth default 300
27305 * @cfg {Number} minHeight default 300
27306 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27307 * @cfg {Boolean} isDocument (true|false) default false
27308 * @cfg {String} url action url
27309 * @cfg {String} paramName default 'imageUpload'
27310 * @cfg {String} method default POST
27311 * @cfg {Boolean} loadMask (true|false) default true
27312 * @cfg {Boolean} loadingText default 'Loading...'
27315 * Create a new UploadCropbox
27316 * @param {Object} config The config object
27319 Roo.bootstrap.UploadCropbox = function(config){
27320 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27324 * @event beforeselectfile
27325 * Fire before select file
27326 * @param {Roo.bootstrap.UploadCropbox} this
27328 "beforeselectfile" : true,
27331 * Fire after initEvent
27332 * @param {Roo.bootstrap.UploadCropbox} this
27337 * Fire after initEvent
27338 * @param {Roo.bootstrap.UploadCropbox} this
27339 * @param {String} data
27344 * Fire when preparing the file data
27345 * @param {Roo.bootstrap.UploadCropbox} this
27346 * @param {Object} file
27351 * Fire when get exception
27352 * @param {Roo.bootstrap.UploadCropbox} this
27353 * @param {XMLHttpRequest} xhr
27355 "exception" : true,
27357 * @event beforeloadcanvas
27358 * Fire before load the canvas
27359 * @param {Roo.bootstrap.UploadCropbox} this
27360 * @param {String} src
27362 "beforeloadcanvas" : true,
27365 * Fire when trash image
27366 * @param {Roo.bootstrap.UploadCropbox} this
27371 * Fire when download the image
27372 * @param {Roo.bootstrap.UploadCropbox} this
27376 * @event footerbuttonclick
27377 * Fire when footerbuttonclick
27378 * @param {Roo.bootstrap.UploadCropbox} this
27379 * @param {String} type
27381 "footerbuttonclick" : true,
27385 * @param {Roo.bootstrap.UploadCropbox} this
27390 * Fire when rotate the image
27391 * @param {Roo.bootstrap.UploadCropbox} this
27392 * @param {String} pos
27397 * Fire when inspect the file
27398 * @param {Roo.bootstrap.UploadCropbox} this
27399 * @param {Object} file
27404 * Fire when xhr upload the file
27405 * @param {Roo.bootstrap.UploadCropbox} this
27406 * @param {Object} data
27411 * Fire when arrange the file data
27412 * @param {Roo.bootstrap.UploadCropbox} this
27413 * @param {Object} formData
27418 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27421 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27423 emptyText : 'Click to upload image',
27424 rotateNotify : 'Image is too small to rotate',
27425 errorTimeout : 3000,
27439 cropType : 'image/jpeg',
27441 canvasLoaded : false,
27442 isDocument : false,
27444 paramName : 'imageUpload',
27446 loadingText : 'Loading...',
27449 getAutoCreate : function()
27453 cls : 'roo-upload-cropbox',
27457 cls : 'roo-upload-cropbox-selector',
27462 cls : 'roo-upload-cropbox-body',
27463 style : 'cursor:pointer',
27467 cls : 'roo-upload-cropbox-preview'
27471 cls : 'roo-upload-cropbox-thumb'
27475 cls : 'roo-upload-cropbox-empty-notify',
27476 html : this.emptyText
27480 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27481 html : this.rotateNotify
27487 cls : 'roo-upload-cropbox-footer',
27490 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27500 onRender : function(ct, position)
27502 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27504 if (this.buttons.length) {
27506 Roo.each(this.buttons, function(bb) {
27508 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27510 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27516 this.maskEl = this.el;
27520 initEvents : function()
27522 this.urlAPI = (window.createObjectURL && window) ||
27523 (window.URL && URL.revokeObjectURL && URL) ||
27524 (window.webkitURL && webkitURL);
27526 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27527 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27529 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27530 this.selectorEl.hide();
27532 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27533 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27535 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27536 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27537 this.thumbEl.hide();
27539 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27540 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27542 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27543 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27544 this.errorEl.hide();
27546 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27547 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27548 this.footerEl.hide();
27550 this.setThumbBoxSize();
27556 this.fireEvent('initial', this);
27563 window.addEventListener("resize", function() { _this.resize(); } );
27565 this.bodyEl.on('click', this.beforeSelectFile, this);
27568 this.bodyEl.on('touchstart', this.onTouchStart, this);
27569 this.bodyEl.on('touchmove', this.onTouchMove, this);
27570 this.bodyEl.on('touchend', this.onTouchEnd, this);
27574 this.bodyEl.on('mousedown', this.onMouseDown, this);
27575 this.bodyEl.on('mousemove', this.onMouseMove, this);
27576 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27577 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27578 Roo.get(document).on('mouseup', this.onMouseUp, this);
27581 this.selectorEl.on('change', this.onFileSelected, this);
27587 this.baseScale = 1;
27589 this.baseRotate = 1;
27590 this.dragable = false;
27591 this.pinching = false;
27594 this.cropData = false;
27595 this.notifyEl.dom.innerHTML = this.emptyText;
27597 this.selectorEl.dom.value = '';
27601 resize : function()
27603 if(this.fireEvent('resize', this) != false){
27604 this.setThumbBoxPosition();
27605 this.setCanvasPosition();
27609 onFooterButtonClick : function(e, el, o, type)
27612 case 'rotate-left' :
27613 this.onRotateLeft(e);
27615 case 'rotate-right' :
27616 this.onRotateRight(e);
27619 this.beforeSelectFile(e);
27634 this.fireEvent('footerbuttonclick', this, type);
27637 beforeSelectFile : function(e)
27639 e.preventDefault();
27641 if(this.fireEvent('beforeselectfile', this) != false){
27642 this.selectorEl.dom.click();
27646 onFileSelected : function(e)
27648 e.preventDefault();
27650 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27654 var file = this.selectorEl.dom.files[0];
27656 if(this.fireEvent('inspect', this, file) != false){
27657 this.prepare(file);
27662 trash : function(e)
27664 this.fireEvent('trash', this);
27667 download : function(e)
27669 this.fireEvent('download', this);
27672 loadCanvas : function(src)
27674 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27678 this.imageEl = document.createElement('img');
27682 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27684 this.imageEl.src = src;
27688 onLoadCanvas : function()
27690 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27691 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27693 this.bodyEl.un('click', this.beforeSelectFile, this);
27695 this.notifyEl.hide();
27696 this.thumbEl.show();
27697 this.footerEl.show();
27699 this.baseRotateLevel();
27701 if(this.isDocument){
27702 this.setThumbBoxSize();
27705 this.setThumbBoxPosition();
27707 this.baseScaleLevel();
27713 this.canvasLoaded = true;
27716 this.maskEl.unmask();
27721 setCanvasPosition : function()
27723 if(!this.canvasEl){
27727 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27728 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27730 this.previewEl.setLeft(pw);
27731 this.previewEl.setTop(ph);
27735 onMouseDown : function(e)
27739 this.dragable = true;
27740 this.pinching = false;
27742 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27743 this.dragable = false;
27747 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27748 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27752 onMouseMove : function(e)
27756 if(!this.canvasLoaded){
27760 if (!this.dragable){
27764 var minX = Math.ceil(this.thumbEl.getLeft(true));
27765 var minY = Math.ceil(this.thumbEl.getTop(true));
27767 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27768 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27770 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27771 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27773 x = x - this.mouseX;
27774 y = y - this.mouseY;
27776 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27777 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27779 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27780 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27782 this.previewEl.setLeft(bgX);
27783 this.previewEl.setTop(bgY);
27785 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27786 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27789 onMouseUp : function(e)
27793 this.dragable = false;
27796 onMouseWheel : function(e)
27800 this.startScale = this.scale;
27802 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27804 if(!this.zoomable()){
27805 this.scale = this.startScale;
27814 zoomable : function()
27816 var minScale = this.thumbEl.getWidth() / this.minWidth;
27818 if(this.minWidth < this.minHeight){
27819 minScale = this.thumbEl.getHeight() / this.minHeight;
27822 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27823 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27827 (this.rotate == 0 || this.rotate == 180) &&
27829 width > this.imageEl.OriginWidth ||
27830 height > this.imageEl.OriginHeight ||
27831 (width < this.minWidth && height < this.minHeight)
27839 (this.rotate == 90 || this.rotate == 270) &&
27841 width > this.imageEl.OriginWidth ||
27842 height > this.imageEl.OriginHeight ||
27843 (width < this.minHeight && height < this.minWidth)
27850 !this.isDocument &&
27851 (this.rotate == 0 || this.rotate == 180) &&
27853 width < this.minWidth ||
27854 width > this.imageEl.OriginWidth ||
27855 height < this.minHeight ||
27856 height > this.imageEl.OriginHeight
27863 !this.isDocument &&
27864 (this.rotate == 90 || this.rotate == 270) &&
27866 width < this.minHeight ||
27867 width > this.imageEl.OriginWidth ||
27868 height < this.minWidth ||
27869 height > this.imageEl.OriginHeight
27879 onRotateLeft : function(e)
27881 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27883 var minScale = this.thumbEl.getWidth() / this.minWidth;
27885 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27886 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27888 this.startScale = this.scale;
27890 while (this.getScaleLevel() < minScale){
27892 this.scale = this.scale + 1;
27894 if(!this.zoomable()){
27899 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27900 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27905 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27912 this.scale = this.startScale;
27914 this.onRotateFail();
27919 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27921 if(this.isDocument){
27922 this.setThumbBoxSize();
27923 this.setThumbBoxPosition();
27924 this.setCanvasPosition();
27929 this.fireEvent('rotate', this, 'left');
27933 onRotateRight : function(e)
27935 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27937 var minScale = this.thumbEl.getWidth() / this.minWidth;
27939 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27940 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27942 this.startScale = this.scale;
27944 while (this.getScaleLevel() < minScale){
27946 this.scale = this.scale + 1;
27948 if(!this.zoomable()){
27953 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27954 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27959 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27966 this.scale = this.startScale;
27968 this.onRotateFail();
27973 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27975 if(this.isDocument){
27976 this.setThumbBoxSize();
27977 this.setThumbBoxPosition();
27978 this.setCanvasPosition();
27983 this.fireEvent('rotate', this, 'right');
27986 onRotateFail : function()
27988 this.errorEl.show(true);
27992 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27997 this.previewEl.dom.innerHTML = '';
27999 var canvasEl = document.createElement("canvas");
28001 var contextEl = canvasEl.getContext("2d");
28003 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28004 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28005 var center = this.imageEl.OriginWidth / 2;
28007 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28008 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28009 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28010 center = this.imageEl.OriginHeight / 2;
28013 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28015 contextEl.translate(center, center);
28016 contextEl.rotate(this.rotate * Math.PI / 180);
28018 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28020 this.canvasEl = document.createElement("canvas");
28022 this.contextEl = this.canvasEl.getContext("2d");
28024 switch (this.rotate) {
28027 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28028 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28030 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28035 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28036 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28038 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28039 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);
28043 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28048 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28049 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28051 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28052 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);
28056 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);
28061 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28062 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28064 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28065 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28069 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);
28076 this.previewEl.appendChild(this.canvasEl);
28078 this.setCanvasPosition();
28083 if(!this.canvasLoaded){
28087 var imageCanvas = document.createElement("canvas");
28089 var imageContext = imageCanvas.getContext("2d");
28091 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28092 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28094 var center = imageCanvas.width / 2;
28096 imageContext.translate(center, center);
28098 imageContext.rotate(this.rotate * Math.PI / 180);
28100 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28102 var canvas = document.createElement("canvas");
28104 var context = canvas.getContext("2d");
28106 canvas.width = this.minWidth;
28107 canvas.height = this.minHeight;
28109 switch (this.rotate) {
28112 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28113 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28115 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28116 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28118 var targetWidth = this.minWidth - 2 * x;
28119 var targetHeight = this.minHeight - 2 * y;
28123 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28124 scale = targetWidth / width;
28127 if(x > 0 && y == 0){
28128 scale = targetHeight / height;
28131 if(x > 0 && y > 0){
28132 scale = targetWidth / width;
28134 if(width < height){
28135 scale = targetHeight / height;
28139 context.scale(scale, scale);
28141 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28142 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28144 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28145 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28147 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28152 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28153 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28155 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28156 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28158 var targetWidth = this.minWidth - 2 * x;
28159 var targetHeight = this.minHeight - 2 * y;
28163 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28164 scale = targetWidth / width;
28167 if(x > 0 && y == 0){
28168 scale = targetHeight / height;
28171 if(x > 0 && y > 0){
28172 scale = targetWidth / width;
28174 if(width < height){
28175 scale = targetHeight / height;
28179 context.scale(scale, scale);
28181 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28182 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28184 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28185 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28187 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28189 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28194 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28195 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28197 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28198 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28200 var targetWidth = this.minWidth - 2 * x;
28201 var targetHeight = this.minHeight - 2 * y;
28205 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28206 scale = targetWidth / width;
28209 if(x > 0 && y == 0){
28210 scale = targetHeight / height;
28213 if(x > 0 && y > 0){
28214 scale = targetWidth / width;
28216 if(width < height){
28217 scale = targetHeight / height;
28221 context.scale(scale, scale);
28223 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28224 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28226 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28227 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28229 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28230 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28232 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28237 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28238 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28240 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28241 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28243 var targetWidth = this.minWidth - 2 * x;
28244 var targetHeight = this.minHeight - 2 * y;
28248 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28249 scale = targetWidth / width;
28252 if(x > 0 && y == 0){
28253 scale = targetHeight / height;
28256 if(x > 0 && y > 0){
28257 scale = targetWidth / width;
28259 if(width < height){
28260 scale = targetHeight / height;
28264 context.scale(scale, scale);
28266 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28267 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28269 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28270 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28272 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28274 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28281 this.cropData = canvas.toDataURL(this.cropType);
28283 if(this.fireEvent('crop', this, this.cropData) !== false){
28284 this.process(this.file, this.cropData);
28291 setThumbBoxSize : function()
28295 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28296 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28297 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28299 this.minWidth = width;
28300 this.minHeight = height;
28302 if(this.rotate == 90 || this.rotate == 270){
28303 this.minWidth = height;
28304 this.minHeight = width;
28309 width = Math.ceil(this.minWidth * height / this.minHeight);
28311 if(this.minWidth > this.minHeight){
28313 height = Math.ceil(this.minHeight * width / this.minWidth);
28316 this.thumbEl.setStyle({
28317 width : width + 'px',
28318 height : height + 'px'
28325 setThumbBoxPosition : function()
28327 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28328 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28330 this.thumbEl.setLeft(x);
28331 this.thumbEl.setTop(y);
28335 baseRotateLevel : function()
28337 this.baseRotate = 1;
28340 typeof(this.exif) != 'undefined' &&
28341 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28342 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28344 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28347 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28351 baseScaleLevel : function()
28355 if(this.isDocument){
28357 if(this.baseRotate == 6 || this.baseRotate == 8){
28359 height = this.thumbEl.getHeight();
28360 this.baseScale = height / this.imageEl.OriginWidth;
28362 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28363 width = this.thumbEl.getWidth();
28364 this.baseScale = width / this.imageEl.OriginHeight;
28370 height = this.thumbEl.getHeight();
28371 this.baseScale = height / this.imageEl.OriginHeight;
28373 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28374 width = this.thumbEl.getWidth();
28375 this.baseScale = width / this.imageEl.OriginWidth;
28381 if(this.baseRotate == 6 || this.baseRotate == 8){
28383 width = this.thumbEl.getHeight();
28384 this.baseScale = width / this.imageEl.OriginHeight;
28386 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28387 height = this.thumbEl.getWidth();
28388 this.baseScale = height / this.imageEl.OriginHeight;
28391 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28392 height = this.thumbEl.getWidth();
28393 this.baseScale = height / this.imageEl.OriginHeight;
28395 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28396 width = this.thumbEl.getHeight();
28397 this.baseScale = width / this.imageEl.OriginWidth;
28404 width = this.thumbEl.getWidth();
28405 this.baseScale = width / this.imageEl.OriginWidth;
28407 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28408 height = this.thumbEl.getHeight();
28409 this.baseScale = height / this.imageEl.OriginHeight;
28412 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28414 height = this.thumbEl.getHeight();
28415 this.baseScale = height / this.imageEl.OriginHeight;
28417 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28418 width = this.thumbEl.getWidth();
28419 this.baseScale = width / this.imageEl.OriginWidth;
28427 getScaleLevel : function()
28429 return this.baseScale * Math.pow(1.1, this.scale);
28432 onTouchStart : function(e)
28434 if(!this.canvasLoaded){
28435 this.beforeSelectFile(e);
28439 var touches = e.browserEvent.touches;
28445 if(touches.length == 1){
28446 this.onMouseDown(e);
28450 if(touches.length != 2){
28456 for(var i = 0, finger; finger = touches[i]; i++){
28457 coords.push(finger.pageX, finger.pageY);
28460 var x = Math.pow(coords[0] - coords[2], 2);
28461 var y = Math.pow(coords[1] - coords[3], 2);
28463 this.startDistance = Math.sqrt(x + y);
28465 this.startScale = this.scale;
28467 this.pinching = true;
28468 this.dragable = false;
28472 onTouchMove : function(e)
28474 if(!this.pinching && !this.dragable){
28478 var touches = e.browserEvent.touches;
28485 this.onMouseMove(e);
28491 for(var i = 0, finger; finger = touches[i]; i++){
28492 coords.push(finger.pageX, finger.pageY);
28495 var x = Math.pow(coords[0] - coords[2], 2);
28496 var y = Math.pow(coords[1] - coords[3], 2);
28498 this.endDistance = Math.sqrt(x + y);
28500 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28502 if(!this.zoomable()){
28503 this.scale = this.startScale;
28511 onTouchEnd : function(e)
28513 this.pinching = false;
28514 this.dragable = false;
28518 process : function(file, crop)
28521 this.maskEl.mask(this.loadingText);
28524 this.xhr = new XMLHttpRequest();
28526 file.xhr = this.xhr;
28528 this.xhr.open(this.method, this.url, true);
28531 "Accept": "application/json",
28532 "Cache-Control": "no-cache",
28533 "X-Requested-With": "XMLHttpRequest"
28536 for (var headerName in headers) {
28537 var headerValue = headers[headerName];
28539 this.xhr.setRequestHeader(headerName, headerValue);
28545 this.xhr.onload = function()
28547 _this.xhrOnLoad(_this.xhr);
28550 this.xhr.onerror = function()
28552 _this.xhrOnError(_this.xhr);
28555 var formData = new FormData();
28557 formData.append('returnHTML', 'NO');
28560 formData.append('crop', crop);
28563 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28564 formData.append(this.paramName, file, file.name);
28567 if(typeof(file.filename) != 'undefined'){
28568 formData.append('filename', file.filename);
28571 if(typeof(file.mimetype) != 'undefined'){
28572 formData.append('mimetype', file.mimetype);
28575 if(this.fireEvent('arrange', this, formData) != false){
28576 this.xhr.send(formData);
28580 xhrOnLoad : function(xhr)
28583 this.maskEl.unmask();
28586 if (xhr.readyState !== 4) {
28587 this.fireEvent('exception', this, xhr);
28591 var response = Roo.decode(xhr.responseText);
28593 if(!response.success){
28594 this.fireEvent('exception', this, xhr);
28598 var response = Roo.decode(xhr.responseText);
28600 this.fireEvent('upload', this, response);
28604 xhrOnError : function()
28607 this.maskEl.unmask();
28610 Roo.log('xhr on error');
28612 var response = Roo.decode(xhr.responseText);
28618 prepare : function(file)
28621 this.maskEl.mask(this.loadingText);
28627 if(typeof(file) === 'string'){
28628 this.loadCanvas(file);
28632 if(!file || !this.urlAPI){
28637 this.cropType = file.type;
28641 if(this.fireEvent('prepare', this, this.file) != false){
28643 var reader = new FileReader();
28645 reader.onload = function (e) {
28646 if (e.target.error) {
28647 Roo.log(e.target.error);
28651 var buffer = e.target.result,
28652 dataView = new DataView(buffer),
28654 maxOffset = dataView.byteLength - 4,
28658 if (dataView.getUint16(0) === 0xffd8) {
28659 while (offset < maxOffset) {
28660 markerBytes = dataView.getUint16(offset);
28662 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28663 markerLength = dataView.getUint16(offset + 2) + 2;
28664 if (offset + markerLength > dataView.byteLength) {
28665 Roo.log('Invalid meta data: Invalid segment size.');
28669 if(markerBytes == 0xffe1){
28670 _this.parseExifData(
28677 offset += markerLength;
28687 var url = _this.urlAPI.createObjectURL(_this.file);
28689 _this.loadCanvas(url);
28694 reader.readAsArrayBuffer(this.file);
28700 parseExifData : function(dataView, offset, length)
28702 var tiffOffset = offset + 10,
28706 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28707 // No Exif data, might be XMP data instead
28711 // Check for the ASCII code for "Exif" (0x45786966):
28712 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28713 // No Exif data, might be XMP data instead
28716 if (tiffOffset + 8 > dataView.byteLength) {
28717 Roo.log('Invalid Exif data: Invalid segment size.');
28720 // Check for the two null bytes:
28721 if (dataView.getUint16(offset + 8) !== 0x0000) {
28722 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28725 // Check the byte alignment:
28726 switch (dataView.getUint16(tiffOffset)) {
28728 littleEndian = true;
28731 littleEndian = false;
28734 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28737 // Check for the TIFF tag marker (0x002A):
28738 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28739 Roo.log('Invalid Exif data: Missing TIFF marker.');
28742 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28743 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28745 this.parseExifTags(
28748 tiffOffset + dirOffset,
28753 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28758 if (dirOffset + 6 > dataView.byteLength) {
28759 Roo.log('Invalid Exif data: Invalid directory offset.');
28762 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28763 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28764 if (dirEndOffset + 4 > dataView.byteLength) {
28765 Roo.log('Invalid Exif data: Invalid directory size.');
28768 for (i = 0; i < tagsNumber; i += 1) {
28772 dirOffset + 2 + 12 * i, // tag offset
28776 // Return the offset to the next directory:
28777 return dataView.getUint32(dirEndOffset, littleEndian);
28780 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28782 var tag = dataView.getUint16(offset, littleEndian);
28784 this.exif[tag] = this.getExifValue(
28788 dataView.getUint16(offset + 2, littleEndian), // tag type
28789 dataView.getUint32(offset + 4, littleEndian), // tag length
28794 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28796 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28805 Roo.log('Invalid Exif data: Invalid tag type.');
28809 tagSize = tagType.size * length;
28810 // Determine if the value is contained in the dataOffset bytes,
28811 // or if the value at the dataOffset is a pointer to the actual data:
28812 dataOffset = tagSize > 4 ?
28813 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28814 if (dataOffset + tagSize > dataView.byteLength) {
28815 Roo.log('Invalid Exif data: Invalid data offset.');
28818 if (length === 1) {
28819 return tagType.getValue(dataView, dataOffset, littleEndian);
28822 for (i = 0; i < length; i += 1) {
28823 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28826 if (tagType.ascii) {
28828 // Concatenate the chars:
28829 for (i = 0; i < values.length; i += 1) {
28831 // Ignore the terminating NULL byte(s):
28832 if (c === '\u0000') {
28844 Roo.apply(Roo.bootstrap.UploadCropbox, {
28846 'Orientation': 0x0112
28850 1: 0, //'top-left',
28852 3: 180, //'bottom-right',
28853 // 4: 'bottom-left',
28855 6: 90, //'right-top',
28856 // 7: 'right-bottom',
28857 8: 270 //'left-bottom'
28861 // byte, 8-bit unsigned int:
28863 getValue: function (dataView, dataOffset) {
28864 return dataView.getUint8(dataOffset);
28868 // ascii, 8-bit byte:
28870 getValue: function (dataView, dataOffset) {
28871 return String.fromCharCode(dataView.getUint8(dataOffset));
28876 // short, 16 bit int:
28878 getValue: function (dataView, dataOffset, littleEndian) {
28879 return dataView.getUint16(dataOffset, littleEndian);
28883 // long, 32 bit int:
28885 getValue: function (dataView, dataOffset, littleEndian) {
28886 return dataView.getUint32(dataOffset, littleEndian);
28890 // rational = two long values, first is numerator, second is denominator:
28892 getValue: function (dataView, dataOffset, littleEndian) {
28893 return dataView.getUint32(dataOffset, littleEndian) /
28894 dataView.getUint32(dataOffset + 4, littleEndian);
28898 // slong, 32 bit signed int:
28900 getValue: function (dataView, dataOffset, littleEndian) {
28901 return dataView.getInt32(dataOffset, littleEndian);
28905 // srational, two slongs, first is numerator, second is denominator:
28907 getValue: function (dataView, dataOffset, littleEndian) {
28908 return dataView.getInt32(dataOffset, littleEndian) /
28909 dataView.getInt32(dataOffset + 4, littleEndian);
28919 cls : 'btn-group roo-upload-cropbox-rotate-left',
28920 action : 'rotate-left',
28924 cls : 'btn btn-default',
28925 html : '<i class="fa fa-undo"></i>'
28931 cls : 'btn-group roo-upload-cropbox-picture',
28932 action : 'picture',
28936 cls : 'btn btn-default',
28937 html : '<i class="fa fa-picture-o"></i>'
28943 cls : 'btn-group roo-upload-cropbox-rotate-right',
28944 action : 'rotate-right',
28948 cls : 'btn btn-default',
28949 html : '<i class="fa fa-repeat"></i>'
28957 cls : 'btn-group roo-upload-cropbox-rotate-left',
28958 action : 'rotate-left',
28962 cls : 'btn btn-default',
28963 html : '<i class="fa fa-undo"></i>'
28969 cls : 'btn-group roo-upload-cropbox-download',
28970 action : 'download',
28974 cls : 'btn btn-default',
28975 html : '<i class="fa fa-download"></i>'
28981 cls : 'btn-group roo-upload-cropbox-crop',
28986 cls : 'btn btn-default',
28987 html : '<i class="fa fa-crop"></i>'
28993 cls : 'btn-group roo-upload-cropbox-trash',
28998 cls : 'btn btn-default',
28999 html : '<i class="fa fa-trash"></i>'
29005 cls : 'btn-group roo-upload-cropbox-rotate-right',
29006 action : 'rotate-right',
29010 cls : 'btn btn-default',
29011 html : '<i class="fa fa-repeat"></i>'
29019 cls : 'btn-group roo-upload-cropbox-rotate-left',
29020 action : 'rotate-left',
29024 cls : 'btn btn-default',
29025 html : '<i class="fa fa-undo"></i>'
29031 cls : 'btn-group roo-upload-cropbox-rotate-right',
29032 action : 'rotate-right',
29036 cls : 'btn btn-default',
29037 html : '<i class="fa fa-repeat"></i>'
29050 * @class Roo.bootstrap.DocumentManager
29051 * @extends Roo.bootstrap.Component
29052 * Bootstrap DocumentManager class
29053 * @cfg {String} paramName default 'imageUpload'
29054 * @cfg {String} toolTipName default 'filename'
29055 * @cfg {String} method default POST
29056 * @cfg {String} url action url
29057 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29058 * @cfg {Boolean} multiple multiple upload default true
29059 * @cfg {Number} thumbSize default 300
29060 * @cfg {String} fieldLabel
29061 * @cfg {Number} labelWidth default 4
29062 * @cfg {String} labelAlign (left|top) default left
29063 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29064 * @cfg {Number} labellg set the width of label (1-12)
29065 * @cfg {Number} labelmd set the width of label (1-12)
29066 * @cfg {Number} labelsm set the width of label (1-12)
29067 * @cfg {Number} labelxs set the width of label (1-12)
29070 * Create a new DocumentManager
29071 * @param {Object} config The config object
29074 Roo.bootstrap.DocumentManager = function(config){
29075 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29078 this.delegates = [];
29083 * Fire when initial the DocumentManager
29084 * @param {Roo.bootstrap.DocumentManager} this
29089 * inspect selected file
29090 * @param {Roo.bootstrap.DocumentManager} this
29091 * @param {File} file
29096 * Fire when xhr load exception
29097 * @param {Roo.bootstrap.DocumentManager} this
29098 * @param {XMLHttpRequest} xhr
29100 "exception" : true,
29102 * @event afterupload
29103 * Fire when xhr load exception
29104 * @param {Roo.bootstrap.DocumentManager} this
29105 * @param {XMLHttpRequest} xhr
29107 "afterupload" : true,
29110 * prepare the form data
29111 * @param {Roo.bootstrap.DocumentManager} this
29112 * @param {Object} formData
29117 * Fire when remove the file
29118 * @param {Roo.bootstrap.DocumentManager} this
29119 * @param {Object} file
29124 * Fire after refresh the file
29125 * @param {Roo.bootstrap.DocumentManager} this
29130 * Fire after click the image
29131 * @param {Roo.bootstrap.DocumentManager} this
29132 * @param {Object} file
29137 * Fire when upload a image and editable set to true
29138 * @param {Roo.bootstrap.DocumentManager} this
29139 * @param {Object} file
29143 * @event beforeselectfile
29144 * Fire before select file
29145 * @param {Roo.bootstrap.DocumentManager} this
29147 "beforeselectfile" : true,
29150 * Fire before process file
29151 * @param {Roo.bootstrap.DocumentManager} this
29152 * @param {Object} file
29156 * @event previewrendered
29157 * Fire when preview rendered
29158 * @param {Roo.bootstrap.DocumentManager} this
29159 * @param {Object} file
29161 "previewrendered" : true,
29164 "previewResize" : true
29169 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29178 paramName : 'imageUpload',
29179 toolTipName : 'filename',
29182 labelAlign : 'left',
29192 getAutoCreate : function()
29194 var managerWidget = {
29196 cls : 'roo-document-manager',
29200 cls : 'roo-document-manager-selector',
29205 cls : 'roo-document-manager-uploader',
29209 cls : 'roo-document-manager-upload-btn',
29210 html : '<i class="fa fa-plus"></i>'
29221 cls : 'column col-md-12',
29226 if(this.fieldLabel.length){
29231 cls : 'column col-md-12',
29232 html : this.fieldLabel
29236 cls : 'column col-md-12',
29241 if(this.labelAlign == 'left'){
29246 html : this.fieldLabel
29255 if(this.labelWidth > 12){
29256 content[0].style = "width: " + this.labelWidth + 'px';
29259 if(this.labelWidth < 13 && this.labelmd == 0){
29260 this.labelmd = this.labelWidth;
29263 if(this.labellg > 0){
29264 content[0].cls += ' col-lg-' + this.labellg;
29265 content[1].cls += ' col-lg-' + (12 - this.labellg);
29268 if(this.labelmd > 0){
29269 content[0].cls += ' col-md-' + this.labelmd;
29270 content[1].cls += ' col-md-' + (12 - this.labelmd);
29273 if(this.labelsm > 0){
29274 content[0].cls += ' col-sm-' + this.labelsm;
29275 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29278 if(this.labelxs > 0){
29279 content[0].cls += ' col-xs-' + this.labelxs;
29280 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29288 cls : 'row clearfix',
29296 initEvents : function()
29298 this.managerEl = this.el.select('.roo-document-manager', true).first();
29299 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29301 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29302 this.selectorEl.hide();
29305 this.selectorEl.attr('multiple', 'multiple');
29308 this.selectorEl.on('change', this.onFileSelected, this);
29310 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29311 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29313 this.uploader.on('click', this.onUploaderClick, this);
29315 this.renderProgressDialog();
29319 window.addEventListener("resize", function() { _this.refresh(); } );
29321 this.fireEvent('initial', this);
29324 renderProgressDialog : function()
29328 this.progressDialog = new Roo.bootstrap.Modal({
29329 cls : 'roo-document-manager-progress-dialog',
29330 allow_close : false,
29341 btnclick : function() {
29342 _this.uploadCancel();
29348 this.progressDialog.render(Roo.get(document.body));
29350 this.progress = new Roo.bootstrap.Progress({
29351 cls : 'roo-document-manager-progress',
29356 this.progress.render(this.progressDialog.getChildContainer());
29358 this.progressBar = new Roo.bootstrap.ProgressBar({
29359 cls : 'roo-document-manager-progress-bar',
29362 aria_valuemax : 12,
29366 this.progressBar.render(this.progress.getChildContainer());
29369 onUploaderClick : function(e)
29371 e.preventDefault();
29373 if(this.fireEvent('beforeselectfile', this) != false){
29374 this.selectorEl.dom.click();
29379 onFileSelected : function(e)
29381 e.preventDefault();
29383 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29387 Roo.each(this.selectorEl.dom.files, function(file){
29388 if(this.fireEvent('inspect', this, file) != false){
29389 this.files.push(file);
29399 this.selectorEl.dom.value = '';
29401 if(!this.files || !this.files.length){
29405 if(this.boxes > 0 && this.files.length > this.boxes){
29406 this.files = this.files.slice(0, this.boxes);
29409 this.uploader.show();
29411 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29412 this.uploader.hide();
29421 Roo.each(this.files, function(file){
29423 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29424 var f = this.renderPreview(file);
29429 if(file.type.indexOf('image') != -1){
29430 this.delegates.push(
29432 _this.process(file);
29433 }).createDelegate(this)
29441 _this.process(file);
29442 }).createDelegate(this)
29447 this.files = files;
29449 this.delegates = this.delegates.concat(docs);
29451 if(!this.delegates.length){
29456 this.progressBar.aria_valuemax = this.delegates.length;
29463 arrange : function()
29465 if(!this.delegates.length){
29466 this.progressDialog.hide();
29471 var delegate = this.delegates.shift();
29473 this.progressDialog.show();
29475 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29477 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29482 refresh : function()
29484 this.uploader.show();
29486 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29487 this.uploader.hide();
29490 Roo.isTouch ? this.closable(false) : this.closable(true);
29492 this.fireEvent('refresh', this);
29495 onRemove : function(e, el, o)
29497 e.preventDefault();
29499 this.fireEvent('remove', this, o);
29503 remove : function(o)
29507 Roo.each(this.files, function(file){
29508 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29517 this.files = files;
29524 Roo.each(this.files, function(file){
29529 file.target.remove();
29538 onClick : function(e, el, o)
29540 e.preventDefault();
29542 this.fireEvent('click', this, o);
29546 closable : function(closable)
29548 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29550 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29562 xhrOnLoad : function(xhr)
29564 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29568 if (xhr.readyState !== 4) {
29570 this.fireEvent('exception', this, xhr);
29574 var response = Roo.decode(xhr.responseText);
29576 if(!response.success){
29578 this.fireEvent('exception', this, xhr);
29582 var file = this.renderPreview(response.data);
29584 this.files.push(file);
29588 this.fireEvent('afterupload', this, xhr);
29592 xhrOnError : function(xhr)
29594 Roo.log('xhr on error');
29596 var response = Roo.decode(xhr.responseText);
29603 process : function(file)
29605 if(this.fireEvent('process', this, file) !== false){
29606 if(this.editable && file.type.indexOf('image') != -1){
29607 this.fireEvent('edit', this, file);
29611 this.uploadStart(file, false);
29618 uploadStart : function(file, crop)
29620 this.xhr = new XMLHttpRequest();
29622 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29627 file.xhr = this.xhr;
29629 this.managerEl.createChild({
29631 cls : 'roo-document-manager-loading',
29635 tooltip : file.name,
29636 cls : 'roo-document-manager-thumb',
29637 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29643 this.xhr.open(this.method, this.url, true);
29646 "Accept": "application/json",
29647 "Cache-Control": "no-cache",
29648 "X-Requested-With": "XMLHttpRequest"
29651 for (var headerName in headers) {
29652 var headerValue = headers[headerName];
29654 this.xhr.setRequestHeader(headerName, headerValue);
29660 this.xhr.onload = function()
29662 _this.xhrOnLoad(_this.xhr);
29665 this.xhr.onerror = function()
29667 _this.xhrOnError(_this.xhr);
29670 var formData = new FormData();
29672 formData.append('returnHTML', 'NO');
29675 formData.append('crop', crop);
29678 formData.append(this.paramName, file, file.name);
29685 if(this.fireEvent('prepare', this, formData, options) != false){
29687 if(options.manually){
29691 this.xhr.send(formData);
29695 this.uploadCancel();
29698 uploadCancel : function()
29704 this.delegates = [];
29706 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29713 renderPreview : function(file)
29715 if(typeof(file.target) != 'undefined' && file.target){
29719 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29721 var previewEl = this.managerEl.createChild({
29723 cls : 'roo-document-manager-preview',
29727 tooltip : file[this.toolTipName],
29728 cls : 'roo-document-manager-thumb',
29729 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29734 html : '<i class="fa fa-times-circle"></i>'
29739 var close = previewEl.select('button.close', true).first();
29741 close.on('click', this.onRemove, this, file);
29743 file.target = previewEl;
29745 var image = previewEl.select('img', true).first();
29749 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29751 image.on('click', this.onClick, this, file);
29753 this.fireEvent('previewrendered', this, file);
29759 onPreviewLoad : function(file, image)
29761 if(typeof(file.target) == 'undefined' || !file.target){
29765 var width = image.dom.naturalWidth || image.dom.width;
29766 var height = image.dom.naturalHeight || image.dom.height;
29768 if(!this.previewResize) {
29772 if(width > height){
29773 file.target.addClass('wide');
29777 file.target.addClass('tall');
29782 uploadFromSource : function(file, crop)
29784 this.xhr = new XMLHttpRequest();
29786 this.managerEl.createChild({
29788 cls : 'roo-document-manager-loading',
29792 tooltip : file.name,
29793 cls : 'roo-document-manager-thumb',
29794 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29800 this.xhr.open(this.method, this.url, true);
29803 "Accept": "application/json",
29804 "Cache-Control": "no-cache",
29805 "X-Requested-With": "XMLHttpRequest"
29808 for (var headerName in headers) {
29809 var headerValue = headers[headerName];
29811 this.xhr.setRequestHeader(headerName, headerValue);
29817 this.xhr.onload = function()
29819 _this.xhrOnLoad(_this.xhr);
29822 this.xhr.onerror = function()
29824 _this.xhrOnError(_this.xhr);
29827 var formData = new FormData();
29829 formData.append('returnHTML', 'NO');
29831 formData.append('crop', crop);
29833 if(typeof(file.filename) != 'undefined'){
29834 formData.append('filename', file.filename);
29837 if(typeof(file.mimetype) != 'undefined'){
29838 formData.append('mimetype', file.mimetype);
29843 if(this.fireEvent('prepare', this, formData) != false){
29844 this.xhr.send(formData);
29854 * @class Roo.bootstrap.DocumentViewer
29855 * @extends Roo.bootstrap.Component
29856 * Bootstrap DocumentViewer class
29857 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29858 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29861 * Create a new DocumentViewer
29862 * @param {Object} config The config object
29865 Roo.bootstrap.DocumentViewer = function(config){
29866 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29871 * Fire after initEvent
29872 * @param {Roo.bootstrap.DocumentViewer} this
29878 * @param {Roo.bootstrap.DocumentViewer} this
29883 * Fire after download button
29884 * @param {Roo.bootstrap.DocumentViewer} this
29889 * Fire after trash button
29890 * @param {Roo.bootstrap.DocumentViewer} this
29897 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29899 showDownload : true,
29903 getAutoCreate : function()
29907 cls : 'roo-document-viewer',
29911 cls : 'roo-document-viewer-body',
29915 cls : 'roo-document-viewer-thumb',
29919 cls : 'roo-document-viewer-image'
29927 cls : 'roo-document-viewer-footer',
29930 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29934 cls : 'btn-group roo-document-viewer-download',
29938 cls : 'btn btn-default',
29939 html : '<i class="fa fa-download"></i>'
29945 cls : 'btn-group roo-document-viewer-trash',
29949 cls : 'btn btn-default',
29950 html : '<i class="fa fa-trash"></i>'
29963 initEvents : function()
29965 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29966 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29968 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29969 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29971 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29972 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29974 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29975 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29977 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29978 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29980 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29981 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29983 this.bodyEl.on('click', this.onClick, this);
29984 this.downloadBtn.on('click', this.onDownload, this);
29985 this.trashBtn.on('click', this.onTrash, this);
29987 this.downloadBtn.hide();
29988 this.trashBtn.hide();
29990 if(this.showDownload){
29991 this.downloadBtn.show();
29994 if(this.showTrash){
29995 this.trashBtn.show();
29998 if(!this.showDownload && !this.showTrash) {
29999 this.footerEl.hide();
30004 initial : function()
30006 this.fireEvent('initial', this);
30010 onClick : function(e)
30012 e.preventDefault();
30014 this.fireEvent('click', this);
30017 onDownload : function(e)
30019 e.preventDefault();
30021 this.fireEvent('download', this);
30024 onTrash : function(e)
30026 e.preventDefault();
30028 this.fireEvent('trash', this);
30040 * @class Roo.bootstrap.NavProgressBar
30041 * @extends Roo.bootstrap.Component
30042 * Bootstrap NavProgressBar class
30045 * Create a new nav progress bar
30046 * @param {Object} config The config object
30049 Roo.bootstrap.NavProgressBar = function(config){
30050 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30052 this.bullets = this.bullets || [];
30054 // Roo.bootstrap.NavProgressBar.register(this);
30058 * Fires when the active item changes
30059 * @param {Roo.bootstrap.NavProgressBar} this
30060 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30061 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30068 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30073 getAutoCreate : function()
30075 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30079 cls : 'roo-navigation-bar-group',
30083 cls : 'roo-navigation-top-bar'
30087 cls : 'roo-navigation-bullets-bar',
30091 cls : 'roo-navigation-bar'
30098 cls : 'roo-navigation-bottom-bar'
30108 initEvents: function()
30113 onRender : function(ct, position)
30115 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30117 if(this.bullets.length){
30118 Roo.each(this.bullets, function(b){
30127 addItem : function(cfg)
30129 var item = new Roo.bootstrap.NavProgressItem(cfg);
30131 item.parentId = this.id;
30132 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30135 var top = new Roo.bootstrap.Element({
30137 cls : 'roo-navigation-bar-text'
30140 var bottom = new Roo.bootstrap.Element({
30142 cls : 'roo-navigation-bar-text'
30145 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30146 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30148 var topText = new Roo.bootstrap.Element({
30150 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30153 var bottomText = new Roo.bootstrap.Element({
30155 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30158 topText.onRender(top.el, null);
30159 bottomText.onRender(bottom.el, null);
30162 item.bottomEl = bottom;
30165 this.barItems.push(item);
30170 getActive : function()
30172 var active = false;
30174 Roo.each(this.barItems, function(v){
30176 if (!v.isActive()) {
30188 setActiveItem : function(item)
30192 Roo.each(this.barItems, function(v){
30193 if (v.rid == item.rid) {
30197 if (v.isActive()) {
30198 v.setActive(false);
30203 item.setActive(true);
30205 this.fireEvent('changed', this, item, prev);
30208 getBarItem: function(rid)
30212 Roo.each(this.barItems, function(e) {
30213 if (e.rid != rid) {
30224 indexOfItem : function(item)
30228 Roo.each(this.barItems, function(v, i){
30230 if (v.rid != item.rid) {
30241 setActiveNext : function()
30243 var i = this.indexOfItem(this.getActive());
30245 if (i > this.barItems.length) {
30249 this.setActiveItem(this.barItems[i+1]);
30252 setActivePrev : function()
30254 var i = this.indexOfItem(this.getActive());
30260 this.setActiveItem(this.barItems[i-1]);
30263 format : function()
30265 if(!this.barItems.length){
30269 var width = 100 / this.barItems.length;
30271 Roo.each(this.barItems, function(i){
30272 i.el.setStyle('width', width + '%');
30273 i.topEl.el.setStyle('width', width + '%');
30274 i.bottomEl.el.setStyle('width', width + '%');
30283 * Nav Progress Item
30288 * @class Roo.bootstrap.NavProgressItem
30289 * @extends Roo.bootstrap.Component
30290 * Bootstrap NavProgressItem class
30291 * @cfg {String} rid the reference id
30292 * @cfg {Boolean} active (true|false) Is item active default false
30293 * @cfg {Boolean} disabled (true|false) Is item active default false
30294 * @cfg {String} html
30295 * @cfg {String} position (top|bottom) text position default bottom
30296 * @cfg {String} icon show icon instead of number
30299 * Create a new NavProgressItem
30300 * @param {Object} config The config object
30302 Roo.bootstrap.NavProgressItem = function(config){
30303 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30308 * The raw click event for the entire grid.
30309 * @param {Roo.bootstrap.NavProgressItem} this
30310 * @param {Roo.EventObject} e
30317 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30323 position : 'bottom',
30326 getAutoCreate : function()
30328 var iconCls = 'roo-navigation-bar-item-icon';
30330 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30334 cls: 'roo-navigation-bar-item',
30344 cfg.cls += ' active';
30347 cfg.cls += ' disabled';
30353 disable : function()
30355 this.setDisabled(true);
30358 enable : function()
30360 this.setDisabled(false);
30363 initEvents: function()
30365 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30367 this.iconEl.on('click', this.onClick, this);
30370 onClick : function(e)
30372 e.preventDefault();
30378 if(this.fireEvent('click', this, e) === false){
30382 this.parent().setActiveItem(this);
30385 isActive: function ()
30387 return this.active;
30390 setActive : function(state)
30392 if(this.active == state){
30396 this.active = state;
30399 this.el.addClass('active');
30403 this.el.removeClass('active');
30408 setDisabled : function(state)
30410 if(this.disabled == state){
30414 this.disabled = state;
30417 this.el.addClass('disabled');
30421 this.el.removeClass('disabled');
30424 tooltipEl : function()
30426 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30439 * @class Roo.bootstrap.FieldLabel
30440 * @extends Roo.bootstrap.Component
30441 * Bootstrap FieldLabel class
30442 * @cfg {String} html contents of the element
30443 * @cfg {String} tag tag of the element default label
30444 * @cfg {String} cls class of the element
30445 * @cfg {String} target label target
30446 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30447 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30448 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30449 * @cfg {String} iconTooltip default "This field is required"
30450 * @cfg {String} indicatorpos (left|right) default left
30453 * Create a new FieldLabel
30454 * @param {Object} config The config object
30457 Roo.bootstrap.FieldLabel = function(config){
30458 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30463 * Fires after the field has been marked as invalid.
30464 * @param {Roo.form.FieldLabel} this
30465 * @param {String} msg The validation message
30470 * Fires after the field has been validated with no errors.
30471 * @param {Roo.form.FieldLabel} this
30477 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30484 invalidClass : 'has-warning',
30485 validClass : 'has-success',
30486 iconTooltip : 'This field is required',
30487 indicatorpos : 'left',
30489 getAutoCreate : function(){
30492 if (!this.allowBlank) {
30498 cls : 'roo-bootstrap-field-label ' + this.cls,
30503 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30504 tooltip : this.iconTooltip
30513 if(this.indicatorpos == 'right'){
30516 cls : 'roo-bootstrap-field-label ' + this.cls,
30525 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30526 tooltip : this.iconTooltip
30535 initEvents: function()
30537 Roo.bootstrap.Element.superclass.initEvents.call(this);
30539 this.indicator = this.indicatorEl();
30541 if(this.indicator){
30542 this.indicator.removeClass('visible');
30543 this.indicator.addClass('invisible');
30546 Roo.bootstrap.FieldLabel.register(this);
30549 indicatorEl : function()
30551 var indicator = this.el.select('i.roo-required-indicator',true).first();
30562 * Mark this field as valid
30564 markValid : function()
30566 if(this.indicator){
30567 this.indicator.removeClass('visible');
30568 this.indicator.addClass('invisible');
30570 if (Roo.bootstrap.version == 3) {
30571 this.el.removeClass(this.invalidClass);
30572 this.el.addClass(this.validClass);
30574 this.el.removeClass('is-invalid');
30575 this.el.addClass('is-valid');
30579 this.fireEvent('valid', this);
30583 * Mark this field as invalid
30584 * @param {String} msg The validation message
30586 markInvalid : function(msg)
30588 if(this.indicator){
30589 this.indicator.removeClass('invisible');
30590 this.indicator.addClass('visible');
30592 if (Roo.bootstrap.version == 3) {
30593 this.el.removeClass(this.validClass);
30594 this.el.addClass(this.invalidClass);
30596 this.el.removeClass('is-valid');
30597 this.el.addClass('is-invalid');
30601 this.fireEvent('invalid', this, msg);
30607 Roo.apply(Roo.bootstrap.FieldLabel, {
30612 * register a FieldLabel Group
30613 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30615 register : function(label)
30617 if(this.groups.hasOwnProperty(label.target)){
30621 this.groups[label.target] = label;
30625 * fetch a FieldLabel Group based on the target
30626 * @param {string} target
30627 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30629 get: function(target) {
30630 if (typeof(this.groups[target]) == 'undefined') {
30634 return this.groups[target] ;
30643 * page DateSplitField.
30649 * @class Roo.bootstrap.DateSplitField
30650 * @extends Roo.bootstrap.Component
30651 * Bootstrap DateSplitField class
30652 * @cfg {string} fieldLabel - the label associated
30653 * @cfg {Number} labelWidth set the width of label (0-12)
30654 * @cfg {String} labelAlign (top|left)
30655 * @cfg {Boolean} dayAllowBlank (true|false) default false
30656 * @cfg {Boolean} monthAllowBlank (true|false) default false
30657 * @cfg {Boolean} yearAllowBlank (true|false) default false
30658 * @cfg {string} dayPlaceholder
30659 * @cfg {string} monthPlaceholder
30660 * @cfg {string} yearPlaceholder
30661 * @cfg {string} dayFormat default 'd'
30662 * @cfg {string} monthFormat default 'm'
30663 * @cfg {string} yearFormat default 'Y'
30664 * @cfg {Number} labellg set the width of label (1-12)
30665 * @cfg {Number} labelmd set the width of label (1-12)
30666 * @cfg {Number} labelsm set the width of label (1-12)
30667 * @cfg {Number} labelxs set the width of label (1-12)
30671 * Create a new DateSplitField
30672 * @param {Object} config The config object
30675 Roo.bootstrap.DateSplitField = function(config){
30676 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30682 * getting the data of years
30683 * @param {Roo.bootstrap.DateSplitField} this
30684 * @param {Object} years
30689 * getting the data of days
30690 * @param {Roo.bootstrap.DateSplitField} this
30691 * @param {Object} days
30696 * Fires after the field has been marked as invalid.
30697 * @param {Roo.form.Field} this
30698 * @param {String} msg The validation message
30703 * Fires after the field has been validated with no errors.
30704 * @param {Roo.form.Field} this
30710 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30713 labelAlign : 'top',
30715 dayAllowBlank : false,
30716 monthAllowBlank : false,
30717 yearAllowBlank : false,
30718 dayPlaceholder : '',
30719 monthPlaceholder : '',
30720 yearPlaceholder : '',
30724 isFormField : true,
30730 getAutoCreate : function()
30734 cls : 'row roo-date-split-field-group',
30739 cls : 'form-hidden-field roo-date-split-field-group-value',
30745 var labelCls = 'col-md-12';
30746 var contentCls = 'col-md-4';
30748 if(this.fieldLabel){
30752 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30756 html : this.fieldLabel
30761 if(this.labelAlign == 'left'){
30763 if(this.labelWidth > 12){
30764 label.style = "width: " + this.labelWidth + 'px';
30767 if(this.labelWidth < 13 && this.labelmd == 0){
30768 this.labelmd = this.labelWidth;
30771 if(this.labellg > 0){
30772 labelCls = ' col-lg-' + this.labellg;
30773 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30776 if(this.labelmd > 0){
30777 labelCls = ' col-md-' + this.labelmd;
30778 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30781 if(this.labelsm > 0){
30782 labelCls = ' col-sm-' + this.labelsm;
30783 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30786 if(this.labelxs > 0){
30787 labelCls = ' col-xs-' + this.labelxs;
30788 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30792 label.cls += ' ' + labelCls;
30794 cfg.cn.push(label);
30797 Roo.each(['day', 'month', 'year'], function(t){
30800 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30807 inputEl: function ()
30809 return this.el.select('.roo-date-split-field-group-value', true).first();
30812 onRender : function(ct, position)
30816 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30818 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30820 this.dayField = new Roo.bootstrap.ComboBox({
30821 allowBlank : this.dayAllowBlank,
30822 alwaysQuery : true,
30823 displayField : 'value',
30826 forceSelection : true,
30828 placeholder : this.dayPlaceholder,
30829 selectOnFocus : true,
30830 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30831 triggerAction : 'all',
30833 valueField : 'value',
30834 store : new Roo.data.SimpleStore({
30835 data : (function() {
30837 _this.fireEvent('days', _this, days);
30840 fields : [ 'value' ]
30843 select : function (_self, record, index)
30845 _this.setValue(_this.getValue());
30850 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30852 this.monthField = new Roo.bootstrap.MonthField({
30853 after : '<i class=\"fa fa-calendar\"></i>',
30854 allowBlank : this.monthAllowBlank,
30855 placeholder : this.monthPlaceholder,
30858 render : function (_self)
30860 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30861 e.preventDefault();
30865 select : function (_self, oldvalue, newvalue)
30867 _this.setValue(_this.getValue());
30872 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30874 this.yearField = new Roo.bootstrap.ComboBox({
30875 allowBlank : this.yearAllowBlank,
30876 alwaysQuery : true,
30877 displayField : 'value',
30880 forceSelection : true,
30882 placeholder : this.yearPlaceholder,
30883 selectOnFocus : true,
30884 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30885 triggerAction : 'all',
30887 valueField : 'value',
30888 store : new Roo.data.SimpleStore({
30889 data : (function() {
30891 _this.fireEvent('years', _this, years);
30894 fields : [ 'value' ]
30897 select : function (_self, record, index)
30899 _this.setValue(_this.getValue());
30904 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30907 setValue : function(v, format)
30909 this.inputEl.dom.value = v;
30911 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30913 var d = Date.parseDate(v, f);
30920 this.setDay(d.format(this.dayFormat));
30921 this.setMonth(d.format(this.monthFormat));
30922 this.setYear(d.format(this.yearFormat));
30929 setDay : function(v)
30931 this.dayField.setValue(v);
30932 this.inputEl.dom.value = this.getValue();
30937 setMonth : function(v)
30939 this.monthField.setValue(v, true);
30940 this.inputEl.dom.value = this.getValue();
30945 setYear : function(v)
30947 this.yearField.setValue(v);
30948 this.inputEl.dom.value = this.getValue();
30953 getDay : function()
30955 return this.dayField.getValue();
30958 getMonth : function()
30960 return this.monthField.getValue();
30963 getYear : function()
30965 return this.yearField.getValue();
30968 getValue : function()
30970 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30972 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30982 this.inputEl.dom.value = '';
30987 validate : function()
30989 var d = this.dayField.validate();
30990 var m = this.monthField.validate();
30991 var y = this.yearField.validate();
30996 (!this.dayAllowBlank && !d) ||
30997 (!this.monthAllowBlank && !m) ||
30998 (!this.yearAllowBlank && !y)
31003 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31012 this.markInvalid();
31017 markValid : function()
31020 var label = this.el.select('label', true).first();
31021 var icon = this.el.select('i.fa-star', true).first();
31027 this.fireEvent('valid', this);
31031 * Mark this field as invalid
31032 * @param {String} msg The validation message
31034 markInvalid : function(msg)
31037 var label = this.el.select('label', true).first();
31038 var icon = this.el.select('i.fa-star', true).first();
31040 if(label && !icon){
31041 this.el.select('.roo-date-split-field-label', true).createChild({
31043 cls : 'text-danger fa fa-lg fa-star',
31044 tooltip : 'This field is required',
31045 style : 'margin-right:5px;'
31049 this.fireEvent('invalid', this, msg);
31052 clearInvalid : function()
31054 var label = this.el.select('label', true).first();
31055 var icon = this.el.select('i.fa-star', true).first();
31061 this.fireEvent('valid', this);
31064 getName: function()
31074 * http://masonry.desandro.com
31076 * The idea is to render all the bricks based on vertical width...
31078 * The original code extends 'outlayer' - we might need to use that....
31084 * @class Roo.bootstrap.LayoutMasonry
31085 * @extends Roo.bootstrap.Component
31086 * Bootstrap Layout Masonry class
31089 * Create a new Element
31090 * @param {Object} config The config object
31093 Roo.bootstrap.LayoutMasonry = function(config){
31095 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31099 Roo.bootstrap.LayoutMasonry.register(this);
31105 * Fire after layout the items
31106 * @param {Roo.bootstrap.LayoutMasonry} this
31107 * @param {Roo.EventObject} e
31114 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31117 * @cfg {Boolean} isLayoutInstant = no animation?
31119 isLayoutInstant : false, // needed?
31122 * @cfg {Number} boxWidth width of the columns
31127 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31132 * @cfg {Number} padWidth padding below box..
31137 * @cfg {Number} gutter gutter width..
31142 * @cfg {Number} maxCols maximum number of columns
31148 * @cfg {Boolean} isAutoInitial defalut true
31150 isAutoInitial : true,
31155 * @cfg {Boolean} isHorizontal defalut false
31157 isHorizontal : false,
31159 currentSize : null,
31165 bricks: null, //CompositeElement
31169 _isLayoutInited : false,
31171 // isAlternative : false, // only use for vertical layout...
31174 * @cfg {Number} alternativePadWidth padding below box..
31176 alternativePadWidth : 50,
31178 selectedBrick : [],
31180 getAutoCreate : function(){
31182 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31186 cls: 'blog-masonary-wrapper ' + this.cls,
31188 cls : 'mas-boxes masonary'
31195 getChildContainer: function( )
31197 if (this.boxesEl) {
31198 return this.boxesEl;
31201 this.boxesEl = this.el.select('.mas-boxes').first();
31203 return this.boxesEl;
31207 initEvents : function()
31211 if(this.isAutoInitial){
31212 Roo.log('hook children rendered');
31213 this.on('childrenrendered', function() {
31214 Roo.log('children rendered');
31220 initial : function()
31222 this.selectedBrick = [];
31224 this.currentSize = this.el.getBox(true);
31226 Roo.EventManager.onWindowResize(this.resize, this);
31228 if(!this.isAutoInitial){
31236 //this.layout.defer(500,this);
31240 resize : function()
31242 var cs = this.el.getBox(true);
31245 this.currentSize.width == cs.width &&
31246 this.currentSize.x == cs.x &&
31247 this.currentSize.height == cs.height &&
31248 this.currentSize.y == cs.y
31250 Roo.log("no change in with or X or Y");
31254 this.currentSize = cs;
31260 layout : function()
31262 this._resetLayout();
31264 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31266 this.layoutItems( isInstant );
31268 this._isLayoutInited = true;
31270 this.fireEvent('layout', this);
31274 _resetLayout : function()
31276 if(this.isHorizontal){
31277 this.horizontalMeasureColumns();
31281 this.verticalMeasureColumns();
31285 verticalMeasureColumns : function()
31287 this.getContainerWidth();
31289 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31290 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31294 var boxWidth = this.boxWidth + this.padWidth;
31296 if(this.containerWidth < this.boxWidth){
31297 boxWidth = this.containerWidth
31300 var containerWidth = this.containerWidth;
31302 var cols = Math.floor(containerWidth / boxWidth);
31304 this.cols = Math.max( cols, 1 );
31306 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31308 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31310 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31312 this.colWidth = boxWidth + avail - this.padWidth;
31314 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31315 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31318 horizontalMeasureColumns : function()
31320 this.getContainerWidth();
31322 var boxWidth = this.boxWidth;
31324 if(this.containerWidth < boxWidth){
31325 boxWidth = this.containerWidth;
31328 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31330 this.el.setHeight(boxWidth);
31334 getContainerWidth : function()
31336 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31339 layoutItems : function( isInstant )
31341 Roo.log(this.bricks);
31343 var items = Roo.apply([], this.bricks);
31345 if(this.isHorizontal){
31346 this._horizontalLayoutItems( items , isInstant );
31350 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31351 // this._verticalAlternativeLayoutItems( items , isInstant );
31355 this._verticalLayoutItems( items , isInstant );
31359 _verticalLayoutItems : function ( items , isInstant)
31361 if ( !items || !items.length ) {
31366 ['xs', 'xs', 'xs', 'tall'],
31367 ['xs', 'xs', 'tall'],
31368 ['xs', 'xs', 'sm'],
31369 ['xs', 'xs', 'xs'],
31375 ['sm', 'xs', 'xs'],
31379 ['tall', 'xs', 'xs', 'xs'],
31380 ['tall', 'xs', 'xs'],
31392 Roo.each(items, function(item, k){
31394 switch (item.size) {
31395 // these layouts take up a full box,
31406 boxes.push([item]);
31429 var filterPattern = function(box, length)
31437 var pattern = box.slice(0, length);
31441 Roo.each(pattern, function(i){
31442 format.push(i.size);
31445 Roo.each(standard, function(s){
31447 if(String(s) != String(format)){
31456 if(!match && length == 1){
31461 filterPattern(box, length - 1);
31465 queue.push(pattern);
31467 box = box.slice(length, box.length);
31469 filterPattern(box, 4);
31475 Roo.each(boxes, function(box, k){
31481 if(box.length == 1){
31486 filterPattern(box, 4);
31490 this._processVerticalLayoutQueue( queue, isInstant );
31494 // _verticalAlternativeLayoutItems : function( items , isInstant )
31496 // if ( !items || !items.length ) {
31500 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31504 _horizontalLayoutItems : function ( items , isInstant)
31506 if ( !items || !items.length || items.length < 3) {
31512 var eItems = items.slice(0, 3);
31514 items = items.slice(3, items.length);
31517 ['xs', 'xs', 'xs', 'wide'],
31518 ['xs', 'xs', 'wide'],
31519 ['xs', 'xs', 'sm'],
31520 ['xs', 'xs', 'xs'],
31526 ['sm', 'xs', 'xs'],
31530 ['wide', 'xs', 'xs', 'xs'],
31531 ['wide', 'xs', 'xs'],
31544 Roo.each(items, function(item, k){
31546 switch (item.size) {
31557 boxes.push([item]);
31581 var filterPattern = function(box, length)
31589 var pattern = box.slice(0, length);
31593 Roo.each(pattern, function(i){
31594 format.push(i.size);
31597 Roo.each(standard, function(s){
31599 if(String(s) != String(format)){
31608 if(!match && length == 1){
31613 filterPattern(box, length - 1);
31617 queue.push(pattern);
31619 box = box.slice(length, box.length);
31621 filterPattern(box, 4);
31627 Roo.each(boxes, function(box, k){
31633 if(box.length == 1){
31638 filterPattern(box, 4);
31645 var pos = this.el.getBox(true);
31649 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31651 var hit_end = false;
31653 Roo.each(queue, function(box){
31657 Roo.each(box, function(b){
31659 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31669 Roo.each(box, function(b){
31671 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31674 mx = Math.max(mx, b.x);
31678 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31682 Roo.each(box, function(b){
31684 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31698 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31701 /** Sets position of item in DOM
31702 * @param {Element} item
31703 * @param {Number} x - horizontal position
31704 * @param {Number} y - vertical position
31705 * @param {Boolean} isInstant - disables transitions
31707 _processVerticalLayoutQueue : function( queue, isInstant )
31709 var pos = this.el.getBox(true);
31714 for (var i = 0; i < this.cols; i++){
31718 Roo.each(queue, function(box, k){
31720 var col = k % this.cols;
31722 Roo.each(box, function(b,kk){
31724 b.el.position('absolute');
31726 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31727 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31729 if(b.size == 'md-left' || b.size == 'md-right'){
31730 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31731 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31734 b.el.setWidth(width);
31735 b.el.setHeight(height);
31737 b.el.select('iframe',true).setSize(width,height);
31741 for (var i = 0; i < this.cols; i++){
31743 if(maxY[i] < maxY[col]){
31748 col = Math.min(col, i);
31752 x = pos.x + col * (this.colWidth + this.padWidth);
31756 var positions = [];
31758 switch (box.length){
31760 positions = this.getVerticalOneBoxColPositions(x, y, box);
31763 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31766 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31769 positions = this.getVerticalFourBoxColPositions(x, y, box);
31775 Roo.each(box, function(b,kk){
31777 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31779 var sz = b.el.getSize();
31781 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31789 for (var i = 0; i < this.cols; i++){
31790 mY = Math.max(mY, maxY[i]);
31793 this.el.setHeight(mY - pos.y);
31797 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31799 // var pos = this.el.getBox(true);
31802 // var maxX = pos.right;
31804 // var maxHeight = 0;
31806 // Roo.each(items, function(item, k){
31810 // item.el.position('absolute');
31812 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31814 // item.el.setWidth(width);
31816 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31818 // item.el.setHeight(height);
31821 // item.el.setXY([x, y], isInstant ? false : true);
31823 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31826 // y = y + height + this.alternativePadWidth;
31828 // maxHeight = maxHeight + height + this.alternativePadWidth;
31832 // this.el.setHeight(maxHeight);
31836 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31838 var pos = this.el.getBox(true);
31843 var maxX = pos.right;
31845 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31847 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31849 Roo.each(queue, function(box, k){
31851 Roo.each(box, function(b, kk){
31853 b.el.position('absolute');
31855 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31856 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31858 if(b.size == 'md-left' || b.size == 'md-right'){
31859 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31860 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31863 b.el.setWidth(width);
31864 b.el.setHeight(height);
31872 var positions = [];
31874 switch (box.length){
31876 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31879 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31882 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31885 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31891 Roo.each(box, function(b,kk){
31893 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31895 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31903 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31905 Roo.each(eItems, function(b,k){
31907 b.size = (k == 0) ? 'sm' : 'xs';
31908 b.x = (k == 0) ? 2 : 1;
31909 b.y = (k == 0) ? 2 : 1;
31911 b.el.position('absolute');
31913 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31915 b.el.setWidth(width);
31917 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31919 b.el.setHeight(height);
31923 var positions = [];
31926 x : maxX - this.unitWidth * 2 - this.gutter,
31931 x : maxX - this.unitWidth,
31932 y : minY + (this.unitWidth + this.gutter) * 2
31936 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31940 Roo.each(eItems, function(b,k){
31942 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31948 getVerticalOneBoxColPositions : function(x, y, box)
31952 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31954 if(box[0].size == 'md-left'){
31958 if(box[0].size == 'md-right'){
31963 x : x + (this.unitWidth + this.gutter) * rand,
31970 getVerticalTwoBoxColPositions : function(x, y, box)
31974 if(box[0].size == 'xs'){
31978 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31982 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31996 x : x + (this.unitWidth + this.gutter) * 2,
31997 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32004 getVerticalThreeBoxColPositions : function(x, y, box)
32008 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32016 x : x + (this.unitWidth + this.gutter) * 1,
32021 x : x + (this.unitWidth + this.gutter) * 2,
32029 if(box[0].size == 'xs' && box[1].size == 'xs'){
32038 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32042 x : x + (this.unitWidth + this.gutter) * 1,
32056 x : x + (this.unitWidth + this.gutter) * 2,
32061 x : x + (this.unitWidth + this.gutter) * 2,
32062 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32069 getVerticalFourBoxColPositions : function(x, y, box)
32073 if(box[0].size == 'xs'){
32082 y : y + (this.unitHeight + this.gutter) * 1
32087 y : y + (this.unitHeight + this.gutter) * 2
32091 x : x + (this.unitWidth + this.gutter) * 1,
32105 x : x + (this.unitWidth + this.gutter) * 2,
32110 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32111 y : y + (this.unitHeight + this.gutter) * 1
32115 x : x + (this.unitWidth + this.gutter) * 2,
32116 y : y + (this.unitWidth + this.gutter) * 2
32123 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32127 if(box[0].size == 'md-left'){
32129 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32136 if(box[0].size == 'md-right'){
32138 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32139 y : minY + (this.unitWidth + this.gutter) * 1
32145 var rand = Math.floor(Math.random() * (4 - box[0].y));
32148 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32149 y : minY + (this.unitWidth + this.gutter) * rand
32156 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32160 if(box[0].size == 'xs'){
32163 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32168 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32169 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32177 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32182 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32183 y : minY + (this.unitWidth + this.gutter) * 2
32190 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32194 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32197 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32202 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32203 y : minY + (this.unitWidth + this.gutter) * 1
32207 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32208 y : minY + (this.unitWidth + this.gutter) * 2
32215 if(box[0].size == 'xs' && box[1].size == 'xs'){
32218 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32223 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32228 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32229 y : minY + (this.unitWidth + this.gutter) * 1
32237 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32242 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32243 y : minY + (this.unitWidth + this.gutter) * 2
32247 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32248 y : minY + (this.unitWidth + this.gutter) * 2
32255 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32259 if(box[0].size == 'xs'){
32262 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32267 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32272 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),
32277 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32278 y : minY + (this.unitWidth + this.gutter) * 1
32286 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32291 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32292 y : minY + (this.unitWidth + this.gutter) * 2
32296 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32297 y : minY + (this.unitWidth + this.gutter) * 2
32301 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),
32302 y : minY + (this.unitWidth + this.gutter) * 2
32310 * remove a Masonry Brick
32311 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32313 removeBrick : function(brick_id)
32319 for (var i = 0; i<this.bricks.length; i++) {
32320 if (this.bricks[i].id == brick_id) {
32321 this.bricks.splice(i,1);
32322 this.el.dom.removeChild(Roo.get(brick_id).dom);
32329 * adds a Masonry Brick
32330 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32332 addBrick : function(cfg)
32334 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32335 //this.register(cn);
32336 cn.parentId = this.id;
32337 cn.render(this.el);
32342 * register a Masonry Brick
32343 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32346 register : function(brick)
32348 this.bricks.push(brick);
32349 brick.masonryId = this.id;
32353 * clear all the Masonry Brick
32355 clearAll : function()
32358 //this.getChildContainer().dom.innerHTML = "";
32359 this.el.dom.innerHTML = '';
32362 getSelected : function()
32364 if (!this.selectedBrick) {
32368 return this.selectedBrick;
32372 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32376 * register a Masonry Layout
32377 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32380 register : function(layout)
32382 this.groups[layout.id] = layout;
32385 * fetch a Masonry Layout based on the masonry layout ID
32386 * @param {string} the masonry layout to add
32387 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32390 get: function(layout_id) {
32391 if (typeof(this.groups[layout_id]) == 'undefined') {
32394 return this.groups[layout_id] ;
32406 * http://masonry.desandro.com
32408 * The idea is to render all the bricks based on vertical width...
32410 * The original code extends 'outlayer' - we might need to use that....
32416 * @class Roo.bootstrap.LayoutMasonryAuto
32417 * @extends Roo.bootstrap.Component
32418 * Bootstrap Layout Masonry class
32421 * Create a new Element
32422 * @param {Object} config The config object
32425 Roo.bootstrap.LayoutMasonryAuto = function(config){
32426 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32429 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32432 * @cfg {Boolean} isFitWidth - resize the width..
32434 isFitWidth : false, // options..
32436 * @cfg {Boolean} isOriginLeft = left align?
32438 isOriginLeft : true,
32440 * @cfg {Boolean} isOriginTop = top align?
32442 isOriginTop : false,
32444 * @cfg {Boolean} isLayoutInstant = no animation?
32446 isLayoutInstant : false, // needed?
32448 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32450 isResizingContainer : true,
32452 * @cfg {Number} columnWidth width of the columns
32458 * @cfg {Number} maxCols maximum number of columns
32463 * @cfg {Number} padHeight padding below box..
32469 * @cfg {Boolean} isAutoInitial defalut true
32472 isAutoInitial : true,
32478 initialColumnWidth : 0,
32479 currentSize : null,
32481 colYs : null, // array.
32488 bricks: null, //CompositeElement
32489 cols : 0, // array?
32490 // element : null, // wrapped now this.el
32491 _isLayoutInited : null,
32494 getAutoCreate : function(){
32498 cls: 'blog-masonary-wrapper ' + this.cls,
32500 cls : 'mas-boxes masonary'
32507 getChildContainer: function( )
32509 if (this.boxesEl) {
32510 return this.boxesEl;
32513 this.boxesEl = this.el.select('.mas-boxes').first();
32515 return this.boxesEl;
32519 initEvents : function()
32523 if(this.isAutoInitial){
32524 Roo.log('hook children rendered');
32525 this.on('childrenrendered', function() {
32526 Roo.log('children rendered');
32533 initial : function()
32535 this.reloadItems();
32537 this.currentSize = this.el.getBox(true);
32539 /// was window resize... - let's see if this works..
32540 Roo.EventManager.onWindowResize(this.resize, this);
32542 if(!this.isAutoInitial){
32547 this.layout.defer(500,this);
32550 reloadItems: function()
32552 this.bricks = this.el.select('.masonry-brick', true);
32554 this.bricks.each(function(b) {
32555 //Roo.log(b.getSize());
32556 if (!b.attr('originalwidth')) {
32557 b.attr('originalwidth', b.getSize().width);
32562 Roo.log(this.bricks.elements.length);
32565 resize : function()
32568 var cs = this.el.getBox(true);
32570 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32571 Roo.log("no change in with or X");
32574 this.currentSize = cs;
32578 layout : function()
32581 this._resetLayout();
32582 //this._manageStamps();
32584 // don't animate first layout
32585 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32586 this.layoutItems( isInstant );
32588 // flag for initalized
32589 this._isLayoutInited = true;
32592 layoutItems : function( isInstant )
32594 //var items = this._getItemsForLayout( this.items );
32595 // original code supports filtering layout items.. we just ignore it..
32597 this._layoutItems( this.bricks , isInstant );
32599 this._postLayout();
32601 _layoutItems : function ( items , isInstant)
32603 //this.fireEvent( 'layout', this, items );
32606 if ( !items || !items.elements.length ) {
32607 // no items, emit event with empty array
32612 items.each(function(item) {
32613 Roo.log("layout item");
32615 // get x/y object from method
32616 var position = this._getItemLayoutPosition( item );
32618 position.item = item;
32619 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32620 queue.push( position );
32623 this._processLayoutQueue( queue );
32625 /** Sets position of item in DOM
32626 * @param {Element} item
32627 * @param {Number} x - horizontal position
32628 * @param {Number} y - vertical position
32629 * @param {Boolean} isInstant - disables transitions
32631 _processLayoutQueue : function( queue )
32633 for ( var i=0, len = queue.length; i < len; i++ ) {
32634 var obj = queue[i];
32635 obj.item.position('absolute');
32636 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32642 * Any logic you want to do after each layout,
32643 * i.e. size the container
32645 _postLayout : function()
32647 this.resizeContainer();
32650 resizeContainer : function()
32652 if ( !this.isResizingContainer ) {
32655 var size = this._getContainerSize();
32657 this.el.setSize(size.width,size.height);
32658 this.boxesEl.setSize(size.width,size.height);
32664 _resetLayout : function()
32666 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32667 this.colWidth = this.el.getWidth();
32668 //this.gutter = this.el.getWidth();
32670 this.measureColumns();
32676 this.colYs.push( 0 );
32682 measureColumns : function()
32684 this.getContainerWidth();
32685 // if columnWidth is 0, default to outerWidth of first item
32686 if ( !this.columnWidth ) {
32687 var firstItem = this.bricks.first();
32688 Roo.log(firstItem);
32689 this.columnWidth = this.containerWidth;
32690 if (firstItem && firstItem.attr('originalwidth') ) {
32691 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32693 // columnWidth fall back to item of first element
32694 Roo.log("set column width?");
32695 this.initialColumnWidth = this.columnWidth ;
32697 // if first elem has no width, default to size of container
32702 if (this.initialColumnWidth) {
32703 this.columnWidth = this.initialColumnWidth;
32708 // column width is fixed at the top - however if container width get's smaller we should
32711 // this bit calcs how man columns..
32713 var columnWidth = this.columnWidth += this.gutter;
32715 // calculate columns
32716 var containerWidth = this.containerWidth + this.gutter;
32718 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32719 // fix rounding errors, typically with gutters
32720 var excess = columnWidth - containerWidth % columnWidth;
32723 // if overshoot is less than a pixel, round up, otherwise floor it
32724 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32725 cols = Math[ mathMethod ]( cols );
32726 this.cols = Math.max( cols, 1 );
32727 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32729 // padding positioning..
32730 var totalColWidth = this.cols * this.columnWidth;
32731 var padavail = this.containerWidth - totalColWidth;
32732 // so for 2 columns - we need 3 'pads'
32734 var padNeeded = (1+this.cols) * this.padWidth;
32736 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32738 this.columnWidth += padExtra
32739 //this.padWidth = Math.floor(padavail / ( this.cols));
32741 // adjust colum width so that padding is fixed??
32743 // we have 3 columns ... total = width * 3
32744 // we have X left over... that should be used by
32746 //if (this.expandC) {
32754 getContainerWidth : function()
32756 /* // container is parent if fit width
32757 var container = this.isFitWidth ? this.element.parentNode : this.element;
32758 // check that this.size and size are there
32759 // IE8 triggers resize on body size change, so they might not be
32761 var size = getSize( container ); //FIXME
32762 this.containerWidth = size && size.innerWidth; //FIXME
32765 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32769 _getItemLayoutPosition : function( item ) // what is item?
32771 // we resize the item to our columnWidth..
32773 item.setWidth(this.columnWidth);
32774 item.autoBoxAdjust = false;
32776 var sz = item.getSize();
32778 // how many columns does this brick span
32779 var remainder = this.containerWidth % this.columnWidth;
32781 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32782 // round if off by 1 pixel, otherwise use ceil
32783 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32784 colSpan = Math.min( colSpan, this.cols );
32786 // normally this should be '1' as we dont' currently allow multi width columns..
32788 var colGroup = this._getColGroup( colSpan );
32789 // get the minimum Y value from the columns
32790 var minimumY = Math.min.apply( Math, colGroup );
32791 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32793 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32795 // position the brick
32797 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32798 y: this.currentSize.y + minimumY + this.padHeight
32802 // apply setHeight to necessary columns
32803 var setHeight = minimumY + sz.height + this.padHeight;
32804 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32806 var setSpan = this.cols + 1 - colGroup.length;
32807 for ( var i = 0; i < setSpan; i++ ) {
32808 this.colYs[ shortColIndex + i ] = setHeight ;
32815 * @param {Number} colSpan - number of columns the element spans
32816 * @returns {Array} colGroup
32818 _getColGroup : function( colSpan )
32820 if ( colSpan < 2 ) {
32821 // if brick spans only one column, use all the column Ys
32826 // how many different places could this brick fit horizontally
32827 var groupCount = this.cols + 1 - colSpan;
32828 // for each group potential horizontal position
32829 for ( var i = 0; i < groupCount; i++ ) {
32830 // make an array of colY values for that one group
32831 var groupColYs = this.colYs.slice( i, i + colSpan );
32832 // and get the max value of the array
32833 colGroup[i] = Math.max.apply( Math, groupColYs );
32838 _manageStamp : function( stamp )
32840 var stampSize = stamp.getSize();
32841 var offset = stamp.getBox();
32842 // get the columns that this stamp affects
32843 var firstX = this.isOriginLeft ? offset.x : offset.right;
32844 var lastX = firstX + stampSize.width;
32845 var firstCol = Math.floor( firstX / this.columnWidth );
32846 firstCol = Math.max( 0, firstCol );
32848 var lastCol = Math.floor( lastX / this.columnWidth );
32849 // lastCol should not go over if multiple of columnWidth #425
32850 lastCol -= lastX % this.columnWidth ? 0 : 1;
32851 lastCol = Math.min( this.cols - 1, lastCol );
32853 // set colYs to bottom of the stamp
32854 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32857 for ( var i = firstCol; i <= lastCol; i++ ) {
32858 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32863 _getContainerSize : function()
32865 this.maxY = Math.max.apply( Math, this.colYs );
32870 if ( this.isFitWidth ) {
32871 size.width = this._getContainerFitWidth();
32877 _getContainerFitWidth : function()
32879 var unusedCols = 0;
32880 // count unused columns
32883 if ( this.colYs[i] !== 0 ) {
32888 // fit container to columns that have been used
32889 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32892 needsResizeLayout : function()
32894 var previousWidth = this.containerWidth;
32895 this.getContainerWidth();
32896 return previousWidth !== this.containerWidth;
32911 * @class Roo.bootstrap.MasonryBrick
32912 * @extends Roo.bootstrap.Component
32913 * Bootstrap MasonryBrick class
32916 * Create a new MasonryBrick
32917 * @param {Object} config The config object
32920 Roo.bootstrap.MasonryBrick = function(config){
32922 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32924 Roo.bootstrap.MasonryBrick.register(this);
32930 * When a MasonryBrick is clcik
32931 * @param {Roo.bootstrap.MasonryBrick} this
32932 * @param {Roo.EventObject} e
32938 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32941 * @cfg {String} title
32945 * @cfg {String} html
32949 * @cfg {String} bgimage
32953 * @cfg {String} videourl
32957 * @cfg {String} cls
32961 * @cfg {String} href
32965 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32970 * @cfg {String} placetitle (center|bottom)
32975 * @cfg {Boolean} isFitContainer defalut true
32977 isFitContainer : true,
32980 * @cfg {Boolean} preventDefault defalut false
32982 preventDefault : false,
32985 * @cfg {Boolean} inverse defalut false
32987 maskInverse : false,
32989 getAutoCreate : function()
32991 if(!this.isFitContainer){
32992 return this.getSplitAutoCreate();
32995 var cls = 'masonry-brick masonry-brick-full';
32997 if(this.href.length){
32998 cls += ' masonry-brick-link';
33001 if(this.bgimage.length){
33002 cls += ' masonry-brick-image';
33005 if(this.maskInverse){
33006 cls += ' mask-inverse';
33009 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33010 cls += ' enable-mask';
33014 cls += ' masonry-' + this.size + '-brick';
33017 if(this.placetitle.length){
33019 switch (this.placetitle) {
33021 cls += ' masonry-center-title';
33024 cls += ' masonry-bottom-title';
33031 if(!this.html.length && !this.bgimage.length){
33032 cls += ' masonry-center-title';
33035 if(!this.html.length && this.bgimage.length){
33036 cls += ' masonry-bottom-title';
33041 cls += ' ' + this.cls;
33045 tag: (this.href.length) ? 'a' : 'div',
33050 cls: 'masonry-brick-mask'
33054 cls: 'masonry-brick-paragraph',
33060 if(this.href.length){
33061 cfg.href = this.href;
33064 var cn = cfg.cn[1].cn;
33066 if(this.title.length){
33069 cls: 'masonry-brick-title',
33074 if(this.html.length){
33077 cls: 'masonry-brick-text',
33082 if (!this.title.length && !this.html.length) {
33083 cfg.cn[1].cls += ' hide';
33086 if(this.bgimage.length){
33089 cls: 'masonry-brick-image-view',
33094 if(this.videourl.length){
33095 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33096 // youtube support only?
33099 cls: 'masonry-brick-image-view',
33102 allowfullscreen : true
33110 getSplitAutoCreate : function()
33112 var cls = 'masonry-brick masonry-brick-split';
33114 if(this.href.length){
33115 cls += ' masonry-brick-link';
33118 if(this.bgimage.length){
33119 cls += ' masonry-brick-image';
33123 cls += ' masonry-' + this.size + '-brick';
33126 switch (this.placetitle) {
33128 cls += ' masonry-center-title';
33131 cls += ' masonry-bottom-title';
33134 if(!this.bgimage.length){
33135 cls += ' masonry-center-title';
33138 if(this.bgimage.length){
33139 cls += ' masonry-bottom-title';
33145 cls += ' ' + this.cls;
33149 tag: (this.href.length) ? 'a' : 'div',
33154 cls: 'masonry-brick-split-head',
33158 cls: 'masonry-brick-paragraph',
33165 cls: 'masonry-brick-split-body',
33171 if(this.href.length){
33172 cfg.href = this.href;
33175 if(this.title.length){
33176 cfg.cn[0].cn[0].cn.push({
33178 cls: 'masonry-brick-title',
33183 if(this.html.length){
33184 cfg.cn[1].cn.push({
33186 cls: 'masonry-brick-text',
33191 if(this.bgimage.length){
33192 cfg.cn[0].cn.push({
33194 cls: 'masonry-brick-image-view',
33199 if(this.videourl.length){
33200 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33201 // youtube support only?
33202 cfg.cn[0].cn.cn.push({
33204 cls: 'masonry-brick-image-view',
33207 allowfullscreen : true
33214 initEvents: function()
33216 switch (this.size) {
33249 this.el.on('touchstart', this.onTouchStart, this);
33250 this.el.on('touchmove', this.onTouchMove, this);
33251 this.el.on('touchend', this.onTouchEnd, this);
33252 this.el.on('contextmenu', this.onContextMenu, this);
33254 this.el.on('mouseenter' ,this.enter, this);
33255 this.el.on('mouseleave', this.leave, this);
33256 this.el.on('click', this.onClick, this);
33259 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33260 this.parent().bricks.push(this);
33265 onClick: function(e, el)
33267 var time = this.endTimer - this.startTimer;
33268 // Roo.log(e.preventDefault());
33271 e.preventDefault();
33276 if(!this.preventDefault){
33280 e.preventDefault();
33282 if (this.activeClass != '') {
33283 this.selectBrick();
33286 this.fireEvent('click', this, e);
33289 enter: function(e, el)
33291 e.preventDefault();
33293 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33297 if(this.bgimage.length && this.html.length){
33298 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33302 leave: function(e, el)
33304 e.preventDefault();
33306 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33310 if(this.bgimage.length && this.html.length){
33311 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33315 onTouchStart: function(e, el)
33317 // e.preventDefault();
33319 this.touchmoved = false;
33321 if(!this.isFitContainer){
33325 if(!this.bgimage.length || !this.html.length){
33329 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33331 this.timer = new Date().getTime();
33335 onTouchMove: function(e, el)
33337 this.touchmoved = true;
33340 onContextMenu : function(e,el)
33342 e.preventDefault();
33343 e.stopPropagation();
33347 onTouchEnd: function(e, el)
33349 // e.preventDefault();
33351 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33358 if(!this.bgimage.length || !this.html.length){
33360 if(this.href.length){
33361 window.location.href = this.href;
33367 if(!this.isFitContainer){
33371 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33373 window.location.href = this.href;
33376 //selection on single brick only
33377 selectBrick : function() {
33379 if (!this.parentId) {
33383 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33384 var index = m.selectedBrick.indexOf(this.id);
33387 m.selectedBrick.splice(index,1);
33388 this.el.removeClass(this.activeClass);
33392 for(var i = 0; i < m.selectedBrick.length; i++) {
33393 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33394 b.el.removeClass(b.activeClass);
33397 m.selectedBrick = [];
33399 m.selectedBrick.push(this.id);
33400 this.el.addClass(this.activeClass);
33404 isSelected : function(){
33405 return this.el.hasClass(this.activeClass);
33410 Roo.apply(Roo.bootstrap.MasonryBrick, {
33413 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33415 * register a Masonry Brick
33416 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33419 register : function(brick)
33421 //this.groups[brick.id] = brick;
33422 this.groups.add(brick.id, brick);
33425 * fetch a masonry brick based on the masonry brick ID
33426 * @param {string} the masonry brick to add
33427 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33430 get: function(brick_id)
33432 // if (typeof(this.groups[brick_id]) == 'undefined') {
33435 // return this.groups[brick_id] ;
33437 if(this.groups.key(brick_id)) {
33438 return this.groups.key(brick_id);
33456 * @class Roo.bootstrap.Brick
33457 * @extends Roo.bootstrap.Component
33458 * Bootstrap Brick class
33461 * Create a new Brick
33462 * @param {Object} config The config object
33465 Roo.bootstrap.Brick = function(config){
33466 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33472 * When a Brick is click
33473 * @param {Roo.bootstrap.Brick} this
33474 * @param {Roo.EventObject} e
33480 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33483 * @cfg {String} title
33487 * @cfg {String} html
33491 * @cfg {String} bgimage
33495 * @cfg {String} cls
33499 * @cfg {String} href
33503 * @cfg {String} video
33507 * @cfg {Boolean} square
33511 getAutoCreate : function()
33513 var cls = 'roo-brick';
33515 if(this.href.length){
33516 cls += ' roo-brick-link';
33519 if(this.bgimage.length){
33520 cls += ' roo-brick-image';
33523 if(!this.html.length && !this.bgimage.length){
33524 cls += ' roo-brick-center-title';
33527 if(!this.html.length && this.bgimage.length){
33528 cls += ' roo-brick-bottom-title';
33532 cls += ' ' + this.cls;
33536 tag: (this.href.length) ? 'a' : 'div',
33541 cls: 'roo-brick-paragraph',
33547 if(this.href.length){
33548 cfg.href = this.href;
33551 var cn = cfg.cn[0].cn;
33553 if(this.title.length){
33556 cls: 'roo-brick-title',
33561 if(this.html.length){
33564 cls: 'roo-brick-text',
33571 if(this.bgimage.length){
33574 cls: 'roo-brick-image-view',
33582 initEvents: function()
33584 if(this.title.length || this.html.length){
33585 this.el.on('mouseenter' ,this.enter, this);
33586 this.el.on('mouseleave', this.leave, this);
33589 Roo.EventManager.onWindowResize(this.resize, this);
33591 if(this.bgimage.length){
33592 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33593 this.imageEl.on('load', this.onImageLoad, this);
33600 onImageLoad : function()
33605 resize : function()
33607 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33609 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33611 if(this.bgimage.length){
33612 var image = this.el.select('.roo-brick-image-view', true).first();
33614 image.setWidth(paragraph.getWidth());
33617 image.setHeight(paragraph.getWidth());
33620 this.el.setHeight(image.getHeight());
33621 paragraph.setHeight(image.getHeight());
33627 enter: function(e, el)
33629 e.preventDefault();
33631 if(this.bgimage.length){
33632 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33633 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33637 leave: function(e, el)
33639 e.preventDefault();
33641 if(this.bgimage.length){
33642 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33643 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33658 * @class Roo.bootstrap.NumberField
33659 * @extends Roo.bootstrap.Input
33660 * Bootstrap NumberField class
33666 * Create a new NumberField
33667 * @param {Object} config The config object
33670 Roo.bootstrap.NumberField = function(config){
33671 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33674 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33677 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33679 allowDecimals : true,
33681 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33683 decimalSeparator : ".",
33685 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33687 decimalPrecision : 2,
33689 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33691 allowNegative : true,
33694 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33698 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33700 minValue : Number.NEGATIVE_INFINITY,
33702 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33704 maxValue : Number.MAX_VALUE,
33706 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33708 minText : "The minimum value for this field is {0}",
33710 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33712 maxText : "The maximum value for this field is {0}",
33714 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33715 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33717 nanText : "{0} is not a valid number",
33719 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33721 thousandsDelimiter : false,
33723 * @cfg {String} valueAlign alignment of value
33725 valueAlign : "left",
33727 getAutoCreate : function()
33729 var hiddenInput = {
33733 cls: 'hidden-number-input'
33737 hiddenInput.name = this.name;
33742 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33744 this.name = hiddenInput.name;
33746 if(cfg.cn.length > 0) {
33747 cfg.cn.push(hiddenInput);
33754 initEvents : function()
33756 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33758 var allowed = "0123456789";
33760 if(this.allowDecimals){
33761 allowed += this.decimalSeparator;
33764 if(this.allowNegative){
33768 if(this.thousandsDelimiter) {
33772 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33774 var keyPress = function(e){
33776 var k = e.getKey();
33778 var c = e.getCharCode();
33781 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33782 allowed.indexOf(String.fromCharCode(c)) === -1
33788 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33792 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33797 this.el.on("keypress", keyPress, this);
33800 validateValue : function(value)
33803 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33807 var num = this.parseValue(value);
33810 this.markInvalid(String.format(this.nanText, value));
33814 if(num < this.minValue){
33815 this.markInvalid(String.format(this.minText, this.minValue));
33819 if(num > this.maxValue){
33820 this.markInvalid(String.format(this.maxText, this.maxValue));
33827 getValue : function()
33829 var v = this.hiddenEl().getValue();
33831 return this.fixPrecision(this.parseValue(v));
33834 parseValue : function(value)
33836 if(this.thousandsDelimiter) {
33838 r = new RegExp(",", "g");
33839 value = value.replace(r, "");
33842 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33843 return isNaN(value) ? '' : value;
33846 fixPrecision : function(value)
33848 if(this.thousandsDelimiter) {
33850 r = new RegExp(",", "g");
33851 value = value.replace(r, "");
33854 var nan = isNaN(value);
33856 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33857 return nan ? '' : value;
33859 return parseFloat(value).toFixed(this.decimalPrecision);
33862 setValue : function(v)
33864 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33870 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33872 this.inputEl().dom.value = (v == '') ? '' :
33873 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33875 if(!this.allowZero && v === '0') {
33876 this.hiddenEl().dom.value = '';
33877 this.inputEl().dom.value = '';
33884 decimalPrecisionFcn : function(v)
33886 return Math.floor(v);
33889 beforeBlur : function()
33891 var v = this.parseValue(this.getRawValue());
33893 if(v || v === 0 || v === ''){
33898 hiddenEl : function()
33900 return this.el.select('input.hidden-number-input',true).first();
33912 * @class Roo.bootstrap.DocumentSlider
33913 * @extends Roo.bootstrap.Component
33914 * Bootstrap DocumentSlider class
33917 * Create a new DocumentViewer
33918 * @param {Object} config The config object
33921 Roo.bootstrap.DocumentSlider = function(config){
33922 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33929 * Fire after initEvent
33930 * @param {Roo.bootstrap.DocumentSlider} this
33935 * Fire after update
33936 * @param {Roo.bootstrap.DocumentSlider} this
33942 * @param {Roo.bootstrap.DocumentSlider} this
33948 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33954 getAutoCreate : function()
33958 cls : 'roo-document-slider',
33962 cls : 'roo-document-slider-header',
33966 cls : 'roo-document-slider-header-title'
33972 cls : 'roo-document-slider-body',
33976 cls : 'roo-document-slider-prev',
33980 cls : 'fa fa-chevron-left'
33986 cls : 'roo-document-slider-thumb',
33990 cls : 'roo-document-slider-image'
33996 cls : 'roo-document-slider-next',
34000 cls : 'fa fa-chevron-right'
34012 initEvents : function()
34014 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34015 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34017 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34018 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34020 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34021 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34023 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34024 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34026 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34027 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34029 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34030 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34032 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34033 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34035 this.thumbEl.on('click', this.onClick, this);
34037 this.prevIndicator.on('click', this.prev, this);
34039 this.nextIndicator.on('click', this.next, this);
34043 initial : function()
34045 if(this.files.length){
34046 this.indicator = 1;
34050 this.fireEvent('initial', this);
34053 update : function()
34055 this.imageEl.attr('src', this.files[this.indicator - 1]);
34057 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34059 this.prevIndicator.show();
34061 if(this.indicator == 1){
34062 this.prevIndicator.hide();
34065 this.nextIndicator.show();
34067 if(this.indicator == this.files.length){
34068 this.nextIndicator.hide();
34071 this.thumbEl.scrollTo('top');
34073 this.fireEvent('update', this);
34076 onClick : function(e)
34078 e.preventDefault();
34080 this.fireEvent('click', this);
34085 e.preventDefault();
34087 this.indicator = Math.max(1, this.indicator - 1);
34094 e.preventDefault();
34096 this.indicator = Math.min(this.files.length, this.indicator + 1);
34110 * @class Roo.bootstrap.RadioSet
34111 * @extends Roo.bootstrap.Input
34112 * Bootstrap RadioSet class
34113 * @cfg {String} indicatorpos (left|right) default left
34114 * @cfg {Boolean} inline (true|false) inline the element (default true)
34115 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34117 * Create a new RadioSet
34118 * @param {Object} config The config object
34121 Roo.bootstrap.RadioSet = function(config){
34123 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34127 Roo.bootstrap.RadioSet.register(this);
34132 * Fires when the element is checked or unchecked.
34133 * @param {Roo.bootstrap.RadioSet} this This radio
34134 * @param {Roo.bootstrap.Radio} item The checked item
34139 * Fires when the element is click.
34140 * @param {Roo.bootstrap.RadioSet} this This radio set
34141 * @param {Roo.bootstrap.Radio} item The checked item
34142 * @param {Roo.EventObject} e The event object
34149 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34157 indicatorpos : 'left',
34159 getAutoCreate : function()
34163 cls : 'roo-radio-set-label',
34167 html : this.fieldLabel
34171 if (Roo.bootstrap.version == 3) {
34174 if(this.indicatorpos == 'left'){
34177 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34178 tooltip : 'This field is required'
34183 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34184 tooltip : 'This field is required'
34190 cls : 'roo-radio-set-items'
34193 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34195 if (align === 'left' && this.fieldLabel.length) {
34198 cls : "roo-radio-set-right",
34204 if(this.labelWidth > 12){
34205 label.style = "width: " + this.labelWidth + 'px';
34208 if(this.labelWidth < 13 && this.labelmd == 0){
34209 this.labelmd = this.labelWidth;
34212 if(this.labellg > 0){
34213 label.cls += ' col-lg-' + this.labellg;
34214 items.cls += ' col-lg-' + (12 - this.labellg);
34217 if(this.labelmd > 0){
34218 label.cls += ' col-md-' + this.labelmd;
34219 items.cls += ' col-md-' + (12 - this.labelmd);
34222 if(this.labelsm > 0){
34223 label.cls += ' col-sm-' + this.labelsm;
34224 items.cls += ' col-sm-' + (12 - this.labelsm);
34227 if(this.labelxs > 0){
34228 label.cls += ' col-xs-' + this.labelxs;
34229 items.cls += ' col-xs-' + (12 - this.labelxs);
34235 cls : 'roo-radio-set',
34239 cls : 'roo-radio-set-input',
34242 value : this.value ? this.value : ''
34249 if(this.weight.length){
34250 cfg.cls += ' roo-radio-' + this.weight;
34254 cfg.cls += ' roo-radio-set-inline';
34258 ['xs','sm','md','lg'].map(function(size){
34259 if (settings[size]) {
34260 cfg.cls += ' col-' + size + '-' + settings[size];
34268 initEvents : function()
34270 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34271 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34273 if(!this.fieldLabel.length){
34274 this.labelEl.hide();
34277 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34278 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34280 this.indicator = this.indicatorEl();
34282 if(this.indicator){
34283 this.indicator.addClass('invisible');
34286 this.originalValue = this.getValue();
34290 inputEl: function ()
34292 return this.el.select('.roo-radio-set-input', true).first();
34295 getChildContainer : function()
34297 return this.itemsEl;
34300 register : function(item)
34302 this.radioes.push(item);
34306 validate : function()
34308 if(this.getVisibilityEl().hasClass('hidden')){
34314 Roo.each(this.radioes, function(i){
34323 if(this.allowBlank) {
34327 if(this.disabled || valid){
34332 this.markInvalid();
34337 markValid : function()
34339 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34340 this.indicatorEl().removeClass('visible');
34341 this.indicatorEl().addClass('invisible');
34345 if (Roo.bootstrap.version == 3) {
34346 this.el.removeClass([this.invalidClass, this.validClass]);
34347 this.el.addClass(this.validClass);
34349 this.el.removeClass(['is-invalid','is-valid']);
34350 this.el.addClass(['is-valid']);
34352 this.fireEvent('valid', this);
34355 markInvalid : function(msg)
34357 if(this.allowBlank || this.disabled){
34361 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34362 this.indicatorEl().removeClass('invisible');
34363 this.indicatorEl().addClass('visible');
34365 if (Roo.bootstrap.version == 3) {
34366 this.el.removeClass([this.invalidClass, this.validClass]);
34367 this.el.addClass(this.invalidClass);
34369 this.el.removeClass(['is-invalid','is-valid']);
34370 this.el.addClass(['is-invalid']);
34373 this.fireEvent('invalid', this, msg);
34377 setValue : function(v, suppressEvent)
34379 if(this.value === v){
34386 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34389 Roo.each(this.radioes, function(i){
34391 i.el.removeClass('checked');
34394 Roo.each(this.radioes, function(i){
34396 if(i.value === v || i.value.toString() === v.toString()){
34398 i.el.addClass('checked');
34400 if(suppressEvent !== true){
34401 this.fireEvent('check', this, i);
34412 clearInvalid : function(){
34414 if(!this.el || this.preventMark){
34418 this.el.removeClass([this.invalidClass]);
34420 this.fireEvent('valid', this);
34425 Roo.apply(Roo.bootstrap.RadioSet, {
34429 register : function(set)
34431 this.groups[set.name] = set;
34434 get: function(name)
34436 if (typeof(this.groups[name]) == 'undefined') {
34440 return this.groups[name] ;
34446 * Ext JS Library 1.1.1
34447 * Copyright(c) 2006-2007, Ext JS, LLC.
34449 * Originally Released Under LGPL - original licence link has changed is not relivant.
34452 * <script type="text/javascript">
34457 * @class Roo.bootstrap.SplitBar
34458 * @extends Roo.util.Observable
34459 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34463 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34464 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34465 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34466 split.minSize = 100;
34467 split.maxSize = 600;
34468 split.animate = true;
34469 split.on('moved', splitterMoved);
34472 * Create a new SplitBar
34473 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34474 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34475 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34476 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34477 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34478 position of the SplitBar).
34480 Roo.bootstrap.SplitBar = function(cfg){
34485 // dragElement : elm
34486 // resizingElement: el,
34488 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34489 // placement : Roo.bootstrap.SplitBar.LEFT ,
34490 // existingProxy ???
34493 this.el = Roo.get(cfg.dragElement, true);
34494 this.el.dom.unselectable = "on";
34496 this.resizingEl = Roo.get(cfg.resizingElement, true);
34500 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34501 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34504 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34507 * The minimum size of the resizing element. (Defaults to 0)
34513 * The maximum size of the resizing element. (Defaults to 2000)
34516 this.maxSize = 2000;
34519 * Whether to animate the transition to the new size
34522 this.animate = false;
34525 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34528 this.useShim = false;
34533 if(!cfg.existingProxy){
34535 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34537 this.proxy = Roo.get(cfg.existingProxy).dom;
34540 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34543 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34546 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34549 this.dragSpecs = {};
34552 * @private The adapter to use to positon and resize elements
34554 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34555 this.adapter.init(this);
34557 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34559 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34560 this.el.addClass("roo-splitbar-h");
34563 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34564 this.el.addClass("roo-splitbar-v");
34570 * Fires when the splitter is moved (alias for {@link #event-moved})
34571 * @param {Roo.bootstrap.SplitBar} this
34572 * @param {Number} newSize the new width or height
34577 * Fires when the splitter is moved
34578 * @param {Roo.bootstrap.SplitBar} this
34579 * @param {Number} newSize the new width or height
34583 * @event beforeresize
34584 * Fires before the splitter is dragged
34585 * @param {Roo.bootstrap.SplitBar} this
34587 "beforeresize" : true,
34589 "beforeapply" : true
34592 Roo.util.Observable.call(this);
34595 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34596 onStartProxyDrag : function(x, y){
34597 this.fireEvent("beforeresize", this);
34599 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34601 o.enableDisplayMode("block");
34602 // all splitbars share the same overlay
34603 Roo.bootstrap.SplitBar.prototype.overlay = o;
34605 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34606 this.overlay.show();
34607 Roo.get(this.proxy).setDisplayed("block");
34608 var size = this.adapter.getElementSize(this);
34609 this.activeMinSize = this.getMinimumSize();;
34610 this.activeMaxSize = this.getMaximumSize();;
34611 var c1 = size - this.activeMinSize;
34612 var c2 = Math.max(this.activeMaxSize - size, 0);
34613 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34614 this.dd.resetConstraints();
34615 this.dd.setXConstraint(
34616 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34617 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34619 this.dd.setYConstraint(0, 0);
34621 this.dd.resetConstraints();
34622 this.dd.setXConstraint(0, 0);
34623 this.dd.setYConstraint(
34624 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34625 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34628 this.dragSpecs.startSize = size;
34629 this.dragSpecs.startPoint = [x, y];
34630 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34634 * @private Called after the drag operation by the DDProxy
34636 onEndProxyDrag : function(e){
34637 Roo.get(this.proxy).setDisplayed(false);
34638 var endPoint = Roo.lib.Event.getXY(e);
34640 this.overlay.hide();
34643 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34644 newSize = this.dragSpecs.startSize +
34645 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34646 endPoint[0] - this.dragSpecs.startPoint[0] :
34647 this.dragSpecs.startPoint[0] - endPoint[0]
34650 newSize = this.dragSpecs.startSize +
34651 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34652 endPoint[1] - this.dragSpecs.startPoint[1] :
34653 this.dragSpecs.startPoint[1] - endPoint[1]
34656 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34657 if(newSize != this.dragSpecs.startSize){
34658 if(this.fireEvent('beforeapply', this, newSize) !== false){
34659 this.adapter.setElementSize(this, newSize);
34660 this.fireEvent("moved", this, newSize);
34661 this.fireEvent("resize", this, newSize);
34667 * Get the adapter this SplitBar uses
34668 * @return The adapter object
34670 getAdapter : function(){
34671 return this.adapter;
34675 * Set the adapter this SplitBar uses
34676 * @param {Object} adapter A SplitBar adapter object
34678 setAdapter : function(adapter){
34679 this.adapter = adapter;
34680 this.adapter.init(this);
34684 * Gets the minimum size for the resizing element
34685 * @return {Number} The minimum size
34687 getMinimumSize : function(){
34688 return this.minSize;
34692 * Sets the minimum size for the resizing element
34693 * @param {Number} minSize The minimum size
34695 setMinimumSize : function(minSize){
34696 this.minSize = minSize;
34700 * Gets the maximum size for the resizing element
34701 * @return {Number} The maximum size
34703 getMaximumSize : function(){
34704 return this.maxSize;
34708 * Sets the maximum size for the resizing element
34709 * @param {Number} maxSize The maximum size
34711 setMaximumSize : function(maxSize){
34712 this.maxSize = maxSize;
34716 * Sets the initialize size for the resizing element
34717 * @param {Number} size The initial size
34719 setCurrentSize : function(size){
34720 var oldAnimate = this.animate;
34721 this.animate = false;
34722 this.adapter.setElementSize(this, size);
34723 this.animate = oldAnimate;
34727 * Destroy this splitbar.
34728 * @param {Boolean} removeEl True to remove the element
34730 destroy : function(removeEl){
34732 this.shim.remove();
34735 this.proxy.parentNode.removeChild(this.proxy);
34743 * @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.
34745 Roo.bootstrap.SplitBar.createProxy = function(dir){
34746 var proxy = new Roo.Element(document.createElement("div"));
34747 proxy.unselectable();
34748 var cls = 'roo-splitbar-proxy';
34749 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34750 document.body.appendChild(proxy.dom);
34755 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34756 * Default Adapter. It assumes the splitter and resizing element are not positioned
34757 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34759 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34762 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34763 // do nothing for now
34764 init : function(s){
34768 * Called before drag operations to get the current size of the resizing element.
34769 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34771 getElementSize : function(s){
34772 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34773 return s.resizingEl.getWidth();
34775 return s.resizingEl.getHeight();
34780 * Called after drag operations to set the size of the resizing element.
34781 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34782 * @param {Number} newSize The new size to set
34783 * @param {Function} onComplete A function to be invoked when resizing is complete
34785 setElementSize : function(s, newSize, onComplete){
34786 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34788 s.resizingEl.setWidth(newSize);
34790 onComplete(s, newSize);
34793 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34798 s.resizingEl.setHeight(newSize);
34800 onComplete(s, newSize);
34803 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34810 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34811 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34812 * Adapter that moves the splitter element to align with the resized sizing element.
34813 * Used with an absolute positioned SplitBar.
34814 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34815 * document.body, make sure you assign an id to the body element.
34817 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34818 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34819 this.container = Roo.get(container);
34822 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34823 init : function(s){
34824 this.basic.init(s);
34827 getElementSize : function(s){
34828 return this.basic.getElementSize(s);
34831 setElementSize : function(s, newSize, onComplete){
34832 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34835 moveSplitter : function(s){
34836 var yes = Roo.bootstrap.SplitBar;
34837 switch(s.placement){
34839 s.el.setX(s.resizingEl.getRight());
34842 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34845 s.el.setY(s.resizingEl.getBottom());
34848 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34855 * Orientation constant - Create a vertical SplitBar
34859 Roo.bootstrap.SplitBar.VERTICAL = 1;
34862 * Orientation constant - Create a horizontal SplitBar
34866 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34869 * Placement constant - The resizing element is to the left of the splitter element
34873 Roo.bootstrap.SplitBar.LEFT = 1;
34876 * Placement constant - The resizing element is to the right of the splitter element
34880 Roo.bootstrap.SplitBar.RIGHT = 2;
34883 * Placement constant - The resizing element is positioned above the splitter element
34887 Roo.bootstrap.SplitBar.TOP = 3;
34890 * Placement constant - The resizing element is positioned under splitter element
34894 Roo.bootstrap.SplitBar.BOTTOM = 4;
34895 Roo.namespace("Roo.bootstrap.layout");/*
34897 * Ext JS Library 1.1.1
34898 * Copyright(c) 2006-2007, Ext JS, LLC.
34900 * Originally Released Under LGPL - original licence link has changed is not relivant.
34903 * <script type="text/javascript">
34907 * @class Roo.bootstrap.layout.Manager
34908 * @extends Roo.bootstrap.Component
34909 * Base class for layout managers.
34911 Roo.bootstrap.layout.Manager = function(config)
34913 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34919 /** false to disable window resize monitoring @type Boolean */
34920 this.monitorWindowResize = true;
34925 * Fires when a layout is performed.
34926 * @param {Roo.LayoutManager} this
34930 * @event regionresized
34931 * Fires when the user resizes a region.
34932 * @param {Roo.LayoutRegion} region The resized region
34933 * @param {Number} newSize The new size (width for east/west, height for north/south)
34935 "regionresized" : true,
34937 * @event regioncollapsed
34938 * Fires when a region is collapsed.
34939 * @param {Roo.LayoutRegion} region The collapsed region
34941 "regioncollapsed" : true,
34943 * @event regionexpanded
34944 * Fires when a region is expanded.
34945 * @param {Roo.LayoutRegion} region The expanded region
34947 "regionexpanded" : true
34949 this.updating = false;
34952 this.el = Roo.get(config.el);
34958 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34963 monitorWindowResize : true,
34969 onRender : function(ct, position)
34972 this.el = Roo.get(ct);
34975 //this.fireEvent('render',this);
34979 initEvents: function()
34983 // ie scrollbar fix
34984 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34985 document.body.scroll = "no";
34986 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34987 this.el.position('relative');
34989 this.id = this.el.id;
34990 this.el.addClass("roo-layout-container");
34991 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34992 if(this.el.dom != document.body ) {
34993 this.el.on('resize', this.layout,this);
34994 this.el.on('show', this.layout,this);
35000 * Returns true if this layout is currently being updated
35001 * @return {Boolean}
35003 isUpdating : function(){
35004 return this.updating;
35008 * Suspend the LayoutManager from doing auto-layouts while
35009 * making multiple add or remove calls
35011 beginUpdate : function(){
35012 this.updating = true;
35016 * Restore auto-layouts and optionally disable the manager from performing a layout
35017 * @param {Boolean} noLayout true to disable a layout update
35019 endUpdate : function(noLayout){
35020 this.updating = false;
35026 layout: function(){
35030 onRegionResized : function(region, newSize){
35031 this.fireEvent("regionresized", region, newSize);
35035 onRegionCollapsed : function(region){
35036 this.fireEvent("regioncollapsed", region);
35039 onRegionExpanded : function(region){
35040 this.fireEvent("regionexpanded", region);
35044 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35045 * performs box-model adjustments.
35046 * @return {Object} The size as an object {width: (the width), height: (the height)}
35048 getViewSize : function()
35051 if(this.el.dom != document.body){
35052 size = this.el.getSize();
35054 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35056 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35057 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35062 * Returns the Element this layout is bound to.
35063 * @return {Roo.Element}
35065 getEl : function(){
35070 * Returns the specified region.
35071 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35072 * @return {Roo.LayoutRegion}
35074 getRegion : function(target){
35075 return this.regions[target.toLowerCase()];
35078 onWindowResize : function(){
35079 if(this.monitorWindowResize){
35086 * Ext JS Library 1.1.1
35087 * Copyright(c) 2006-2007, Ext JS, LLC.
35089 * Originally Released Under LGPL - original licence link has changed is not relivant.
35092 * <script type="text/javascript">
35095 * @class Roo.bootstrap.layout.Border
35096 * @extends Roo.bootstrap.layout.Manager
35097 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35098 * please see: examples/bootstrap/nested.html<br><br>
35100 <b>The container the layout is rendered into can be either the body element or any other element.
35101 If it is not the body element, the container needs to either be an absolute positioned element,
35102 or you will need to add "position:relative" to the css of the container. You will also need to specify
35103 the container size if it is not the body element.</b>
35106 * Create a new Border
35107 * @param {Object} config Configuration options
35109 Roo.bootstrap.layout.Border = function(config){
35110 config = config || {};
35111 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35115 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35116 if(config[region]){
35117 config[region].region = region;
35118 this.addRegion(config[region]);
35124 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35126 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35128 * Creates and adds a new region if it doesn't already exist.
35129 * @param {String} target The target region key (north, south, east, west or center).
35130 * @param {Object} config The regions config object
35131 * @return {BorderLayoutRegion} The new region
35133 addRegion : function(config)
35135 if(!this.regions[config.region]){
35136 var r = this.factory(config);
35137 this.bindRegion(r);
35139 return this.regions[config.region];
35143 bindRegion : function(r){
35144 this.regions[r.config.region] = r;
35146 r.on("visibilitychange", this.layout, this);
35147 r.on("paneladded", this.layout, this);
35148 r.on("panelremoved", this.layout, this);
35149 r.on("invalidated", this.layout, this);
35150 r.on("resized", this.onRegionResized, this);
35151 r.on("collapsed", this.onRegionCollapsed, this);
35152 r.on("expanded", this.onRegionExpanded, this);
35156 * Performs a layout update.
35158 layout : function()
35160 if(this.updating) {
35164 // render all the rebions if they have not been done alreayd?
35165 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35166 if(this.regions[region] && !this.regions[region].bodyEl){
35167 this.regions[region].onRender(this.el)
35171 var size = this.getViewSize();
35172 var w = size.width;
35173 var h = size.height;
35178 //var x = 0, y = 0;
35180 var rs = this.regions;
35181 var north = rs["north"];
35182 var south = rs["south"];
35183 var west = rs["west"];
35184 var east = rs["east"];
35185 var center = rs["center"];
35186 //if(this.hideOnLayout){ // not supported anymore
35187 //c.el.setStyle("display", "none");
35189 if(north && north.isVisible()){
35190 var b = north.getBox();
35191 var m = north.getMargins();
35192 b.width = w - (m.left+m.right);
35195 centerY = b.height + b.y + m.bottom;
35196 centerH -= centerY;
35197 north.updateBox(this.safeBox(b));
35199 if(south && south.isVisible()){
35200 var b = south.getBox();
35201 var m = south.getMargins();
35202 b.width = w - (m.left+m.right);
35204 var totalHeight = (b.height + m.top + m.bottom);
35205 b.y = h - totalHeight + m.top;
35206 centerH -= totalHeight;
35207 south.updateBox(this.safeBox(b));
35209 if(west && west.isVisible()){
35210 var b = west.getBox();
35211 var m = west.getMargins();
35212 b.height = centerH - (m.top+m.bottom);
35214 b.y = centerY + m.top;
35215 var totalWidth = (b.width + m.left + m.right);
35216 centerX += totalWidth;
35217 centerW -= totalWidth;
35218 west.updateBox(this.safeBox(b));
35220 if(east && east.isVisible()){
35221 var b = east.getBox();
35222 var m = east.getMargins();
35223 b.height = centerH - (m.top+m.bottom);
35224 var totalWidth = (b.width + m.left + m.right);
35225 b.x = w - totalWidth + m.left;
35226 b.y = centerY + m.top;
35227 centerW -= totalWidth;
35228 east.updateBox(this.safeBox(b));
35231 var m = center.getMargins();
35233 x: centerX + m.left,
35234 y: centerY + m.top,
35235 width: centerW - (m.left+m.right),
35236 height: centerH - (m.top+m.bottom)
35238 //if(this.hideOnLayout){
35239 //center.el.setStyle("display", "block");
35241 center.updateBox(this.safeBox(centerBox));
35244 this.fireEvent("layout", this);
35248 safeBox : function(box){
35249 box.width = Math.max(0, box.width);
35250 box.height = Math.max(0, box.height);
35255 * Adds a ContentPanel (or subclass) to this layout.
35256 * @param {String} target The target region key (north, south, east, west or center).
35257 * @param {Roo.ContentPanel} panel The panel to add
35258 * @return {Roo.ContentPanel} The added panel
35260 add : function(target, panel){
35262 target = target.toLowerCase();
35263 return this.regions[target].add(panel);
35267 * Remove a ContentPanel (or subclass) to this layout.
35268 * @param {String} target The target region key (north, south, east, west or center).
35269 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35270 * @return {Roo.ContentPanel} The removed panel
35272 remove : function(target, panel){
35273 target = target.toLowerCase();
35274 return this.regions[target].remove(panel);
35278 * Searches all regions for a panel with the specified id
35279 * @param {String} panelId
35280 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35282 findPanel : function(panelId){
35283 var rs = this.regions;
35284 for(var target in rs){
35285 if(typeof rs[target] != "function"){
35286 var p = rs[target].getPanel(panelId);
35296 * Searches all regions for a panel with the specified id and activates (shows) it.
35297 * @param {String/ContentPanel} panelId The panels id or the panel itself
35298 * @return {Roo.ContentPanel} The shown panel or null
35300 showPanel : function(panelId) {
35301 var rs = this.regions;
35302 for(var target in rs){
35303 var r = rs[target];
35304 if(typeof r != "function"){
35305 if(r.hasPanel(panelId)){
35306 return r.showPanel(panelId);
35314 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35315 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35318 restoreState : function(provider){
35320 provider = Roo.state.Manager;
35322 var sm = new Roo.LayoutStateManager();
35323 sm.init(this, provider);
35329 * Adds a xtype elements to the layout.
35333 xtype : 'ContentPanel',
35340 xtype : 'NestedLayoutPanel',
35346 items : [ ... list of content panels or nested layout panels.. ]
35350 * @param {Object} cfg Xtype definition of item to add.
35352 addxtype : function(cfg)
35354 // basically accepts a pannel...
35355 // can accept a layout region..!?!?
35356 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35359 // theory? children can only be panels??
35361 //if (!cfg.xtype.match(/Panel$/)) {
35366 if (typeof(cfg.region) == 'undefined') {
35367 Roo.log("Failed to add Panel, region was not set");
35371 var region = cfg.region;
35377 xitems = cfg.items;
35384 case 'Content': // ContentPanel (el, cfg)
35385 case 'Scroll': // ContentPanel (el, cfg)
35387 cfg.autoCreate = cfg.autoCreate || true;
35388 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35390 // var el = this.el.createChild();
35391 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35394 this.add(region, ret);
35398 case 'TreePanel': // our new panel!
35399 cfg.el = this.el.createChild();
35400 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35401 this.add(region, ret);
35406 // create a new Layout (which is a Border Layout...
35408 var clayout = cfg.layout;
35409 clayout.el = this.el.createChild();
35410 clayout.items = clayout.items || [];
35414 // replace this exitems with the clayout ones..
35415 xitems = clayout.items;
35417 // force background off if it's in center...
35418 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35419 cfg.background = false;
35421 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35424 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35425 //console.log('adding nested layout panel ' + cfg.toSource());
35426 this.add(region, ret);
35427 nb = {}; /// find first...
35432 // needs grid and region
35434 //var el = this.getRegion(region).el.createChild();
35436 *var el = this.el.createChild();
35437 // create the grid first...
35438 cfg.grid.container = el;
35439 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35442 if (region == 'center' && this.active ) {
35443 cfg.background = false;
35446 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35448 this.add(region, ret);
35450 if (cfg.background) {
35451 // render grid on panel activation (if panel background)
35452 ret.on('activate', function(gp) {
35453 if (!gp.grid.rendered) {
35454 // gp.grid.render(el);
35458 // cfg.grid.render(el);
35464 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35465 // it was the old xcomponent building that caused this before.
35466 // espeically if border is the top element in the tree.
35476 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35478 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35479 this.add(region, ret);
35483 throw "Can not add '" + cfg.xtype + "' to Border";
35489 this.beginUpdate();
35493 Roo.each(xitems, function(i) {
35494 region = nb && i.region ? i.region : false;
35496 var add = ret.addxtype(i);
35499 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35500 if (!i.background) {
35501 abn[region] = nb[region] ;
35508 // make the last non-background panel active..
35509 //if (nb) { Roo.log(abn); }
35512 for(var r in abn) {
35513 region = this.getRegion(r);
35515 // tried using nb[r], but it does not work..
35517 region.showPanel(abn[r]);
35528 factory : function(cfg)
35531 var validRegions = Roo.bootstrap.layout.Border.regions;
35533 var target = cfg.region;
35536 var r = Roo.bootstrap.layout;
35540 return new r.North(cfg);
35542 return new r.South(cfg);
35544 return new r.East(cfg);
35546 return new r.West(cfg);
35548 return new r.Center(cfg);
35550 throw 'Layout region "'+target+'" not supported.';
35557 * Ext JS Library 1.1.1
35558 * Copyright(c) 2006-2007, Ext JS, LLC.
35560 * Originally Released Under LGPL - original licence link has changed is not relivant.
35563 * <script type="text/javascript">
35567 * @class Roo.bootstrap.layout.Basic
35568 * @extends Roo.util.Observable
35569 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35570 * and does not have a titlebar, tabs or any other features. All it does is size and position
35571 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35572 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35573 * @cfg {string} region the region that it inhabits..
35574 * @cfg {bool} skipConfig skip config?
35578 Roo.bootstrap.layout.Basic = function(config){
35580 this.mgr = config.mgr;
35582 this.position = config.region;
35584 var skipConfig = config.skipConfig;
35588 * @scope Roo.BasicLayoutRegion
35592 * @event beforeremove
35593 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35594 * @param {Roo.LayoutRegion} this
35595 * @param {Roo.ContentPanel} panel The panel
35596 * @param {Object} e The cancel event object
35598 "beforeremove" : true,
35600 * @event invalidated
35601 * Fires when the layout for this region is changed.
35602 * @param {Roo.LayoutRegion} this
35604 "invalidated" : true,
35606 * @event visibilitychange
35607 * Fires when this region is shown or hidden
35608 * @param {Roo.LayoutRegion} this
35609 * @param {Boolean} visibility true or false
35611 "visibilitychange" : true,
35613 * @event paneladded
35614 * Fires when a panel is added.
35615 * @param {Roo.LayoutRegion} this
35616 * @param {Roo.ContentPanel} panel The panel
35618 "paneladded" : true,
35620 * @event panelremoved
35621 * Fires when a panel is removed.
35622 * @param {Roo.LayoutRegion} this
35623 * @param {Roo.ContentPanel} panel The panel
35625 "panelremoved" : true,
35627 * @event beforecollapse
35628 * Fires when this region before collapse.
35629 * @param {Roo.LayoutRegion} this
35631 "beforecollapse" : true,
35634 * Fires when this region is collapsed.
35635 * @param {Roo.LayoutRegion} this
35637 "collapsed" : true,
35640 * Fires when this region is expanded.
35641 * @param {Roo.LayoutRegion} this
35646 * Fires when this region is slid into view.
35647 * @param {Roo.LayoutRegion} this
35649 "slideshow" : true,
35652 * Fires when this region slides out of view.
35653 * @param {Roo.LayoutRegion} this
35655 "slidehide" : true,
35657 * @event panelactivated
35658 * Fires when a panel is activated.
35659 * @param {Roo.LayoutRegion} this
35660 * @param {Roo.ContentPanel} panel The activated panel
35662 "panelactivated" : true,
35665 * Fires when the user resizes this region.
35666 * @param {Roo.LayoutRegion} this
35667 * @param {Number} newSize The new size (width for east/west, height for north/south)
35671 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35672 this.panels = new Roo.util.MixedCollection();
35673 this.panels.getKey = this.getPanelId.createDelegate(this);
35675 this.activePanel = null;
35676 // ensure listeners are added...
35678 if (config.listeners || config.events) {
35679 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35680 listeners : config.listeners || {},
35681 events : config.events || {}
35685 if(skipConfig !== true){
35686 this.applyConfig(config);
35690 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35692 getPanelId : function(p){
35696 applyConfig : function(config){
35697 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35698 this.config = config;
35703 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35704 * the width, for horizontal (north, south) the height.
35705 * @param {Number} newSize The new width or height
35707 resizeTo : function(newSize){
35708 var el = this.el ? this.el :
35709 (this.activePanel ? this.activePanel.getEl() : null);
35711 switch(this.position){
35714 el.setWidth(newSize);
35715 this.fireEvent("resized", this, newSize);
35719 el.setHeight(newSize);
35720 this.fireEvent("resized", this, newSize);
35726 getBox : function(){
35727 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35730 getMargins : function(){
35731 return this.margins;
35734 updateBox : function(box){
35736 var el = this.activePanel.getEl();
35737 el.dom.style.left = box.x + "px";
35738 el.dom.style.top = box.y + "px";
35739 this.activePanel.setSize(box.width, box.height);
35743 * Returns the container element for this region.
35744 * @return {Roo.Element}
35746 getEl : function(){
35747 return this.activePanel;
35751 * Returns true if this region is currently visible.
35752 * @return {Boolean}
35754 isVisible : function(){
35755 return this.activePanel ? true : false;
35758 setActivePanel : function(panel){
35759 panel = this.getPanel(panel);
35760 if(this.activePanel && this.activePanel != panel){
35761 this.activePanel.setActiveState(false);
35762 this.activePanel.getEl().setLeftTop(-10000,-10000);
35764 this.activePanel = panel;
35765 panel.setActiveState(true);
35767 panel.setSize(this.box.width, this.box.height);
35769 this.fireEvent("panelactivated", this, panel);
35770 this.fireEvent("invalidated");
35774 * Show the specified panel.
35775 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35776 * @return {Roo.ContentPanel} The shown panel or null
35778 showPanel : function(panel){
35779 panel = this.getPanel(panel);
35781 this.setActivePanel(panel);
35787 * Get the active panel for this region.
35788 * @return {Roo.ContentPanel} The active panel or null
35790 getActivePanel : function(){
35791 return this.activePanel;
35795 * Add the passed ContentPanel(s)
35796 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35797 * @return {Roo.ContentPanel} The panel added (if only one was added)
35799 add : function(panel){
35800 if(arguments.length > 1){
35801 for(var i = 0, len = arguments.length; i < len; i++) {
35802 this.add(arguments[i]);
35806 if(this.hasPanel(panel)){
35807 this.showPanel(panel);
35810 var el = panel.getEl();
35811 if(el.dom.parentNode != this.mgr.el.dom){
35812 this.mgr.el.dom.appendChild(el.dom);
35814 if(panel.setRegion){
35815 panel.setRegion(this);
35817 this.panels.add(panel);
35818 el.setStyle("position", "absolute");
35819 if(!panel.background){
35820 this.setActivePanel(panel);
35821 if(this.config.initialSize && this.panels.getCount()==1){
35822 this.resizeTo(this.config.initialSize);
35825 this.fireEvent("paneladded", this, panel);
35830 * Returns true if the panel is in this region.
35831 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35832 * @return {Boolean}
35834 hasPanel : function(panel){
35835 if(typeof panel == "object"){ // must be panel obj
35836 panel = panel.getId();
35838 return this.getPanel(panel) ? true : false;
35842 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35843 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35844 * @param {Boolean} preservePanel Overrides the config preservePanel option
35845 * @return {Roo.ContentPanel} The panel that was removed
35847 remove : function(panel, preservePanel){
35848 panel = this.getPanel(panel);
35853 this.fireEvent("beforeremove", this, panel, e);
35854 if(e.cancel === true){
35857 var panelId = panel.getId();
35858 this.panels.removeKey(panelId);
35863 * Returns the panel specified or null if it's not in this region.
35864 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35865 * @return {Roo.ContentPanel}
35867 getPanel : function(id){
35868 if(typeof id == "object"){ // must be panel obj
35871 return this.panels.get(id);
35875 * Returns this regions position (north/south/east/west/center).
35878 getPosition: function(){
35879 return this.position;
35883 * Ext JS Library 1.1.1
35884 * Copyright(c) 2006-2007, Ext JS, LLC.
35886 * Originally Released Under LGPL - original licence link has changed is not relivant.
35889 * <script type="text/javascript">
35893 * @class Roo.bootstrap.layout.Region
35894 * @extends Roo.bootstrap.layout.Basic
35895 * This class represents a region in a layout manager.
35897 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35898 * @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})
35899 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35900 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35901 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35902 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35903 * @cfg {String} title The title for the region (overrides panel titles)
35904 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35905 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35906 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35907 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35908 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35909 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35910 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35911 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35912 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35913 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35915 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35916 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35917 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35918 * @cfg {Number} width For East/West panels
35919 * @cfg {Number} height For North/South panels
35920 * @cfg {Boolean} split To show the splitter
35921 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35923 * @cfg {string} cls Extra CSS classes to add to region
35925 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35926 * @cfg {string} region the region that it inhabits..
35929 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35930 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35932 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35933 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35934 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35936 Roo.bootstrap.layout.Region = function(config)
35938 this.applyConfig(config);
35940 var mgr = config.mgr;
35941 var pos = config.region;
35942 config.skipConfig = true;
35943 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35946 this.onRender(mgr.el);
35949 this.visible = true;
35950 this.collapsed = false;
35951 this.unrendered_panels = [];
35954 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35956 position: '', // set by wrapper (eg. north/south etc..)
35957 unrendered_panels : null, // unrendered panels.
35958 createBody : function(){
35959 /** This region's body element
35960 * @type Roo.Element */
35961 this.bodyEl = this.el.createChild({
35963 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35967 onRender: function(ctr, pos)
35969 var dh = Roo.DomHelper;
35970 /** This region's container element
35971 * @type Roo.Element */
35972 this.el = dh.append(ctr.dom, {
35974 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35976 /** This region's title element
35977 * @type Roo.Element */
35979 this.titleEl = dh.append(this.el.dom,
35982 unselectable: "on",
35983 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35985 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35986 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35989 this.titleEl.enableDisplayMode();
35990 /** This region's title text element
35991 * @type HTMLElement */
35992 this.titleTextEl = this.titleEl.dom.firstChild;
35993 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35995 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35996 this.closeBtn.enableDisplayMode();
35997 this.closeBtn.on("click", this.closeClicked, this);
35998 this.closeBtn.hide();
36000 this.createBody(this.config);
36001 if(this.config.hideWhenEmpty){
36003 this.on("paneladded", this.validateVisibility, this);
36004 this.on("panelremoved", this.validateVisibility, this);
36006 if(this.autoScroll){
36007 this.bodyEl.setStyle("overflow", "auto");
36009 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36011 //if(c.titlebar !== false){
36012 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36013 this.titleEl.hide();
36015 this.titleEl.show();
36016 if(this.config.title){
36017 this.titleTextEl.innerHTML = this.config.title;
36021 if(this.config.collapsed){
36022 this.collapse(true);
36024 if(this.config.hidden){
36028 if (this.unrendered_panels && this.unrendered_panels.length) {
36029 for (var i =0;i< this.unrendered_panels.length; i++) {
36030 this.add(this.unrendered_panels[i]);
36032 this.unrendered_panels = null;
36038 applyConfig : function(c)
36041 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36042 var dh = Roo.DomHelper;
36043 if(c.titlebar !== false){
36044 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36045 this.collapseBtn.on("click", this.collapse, this);
36046 this.collapseBtn.enableDisplayMode();
36048 if(c.showPin === true || this.showPin){
36049 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36050 this.stickBtn.enableDisplayMode();
36051 this.stickBtn.on("click", this.expand, this);
36052 this.stickBtn.hide();
36057 /** This region's collapsed element
36058 * @type Roo.Element */
36061 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36062 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36065 if(c.floatable !== false){
36066 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36067 this.collapsedEl.on("click", this.collapseClick, this);
36070 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36071 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36072 id: "message", unselectable: "on", style:{"float":"left"}});
36073 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36075 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36076 this.expandBtn.on("click", this.expand, this);
36080 if(this.collapseBtn){
36081 this.collapseBtn.setVisible(c.collapsible == true);
36084 this.cmargins = c.cmargins || this.cmargins ||
36085 (this.position == "west" || this.position == "east" ?
36086 {top: 0, left: 2, right:2, bottom: 0} :
36087 {top: 2, left: 0, right:0, bottom: 2});
36089 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36092 this.bottomTabs = c.tabPosition != "top";
36094 this.autoScroll = c.autoScroll || false;
36099 this.duration = c.duration || .30;
36100 this.slideDuration = c.slideDuration || .45;
36105 * Returns true if this region is currently visible.
36106 * @return {Boolean}
36108 isVisible : function(){
36109 return this.visible;
36113 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36114 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36116 //setCollapsedTitle : function(title){
36117 // title = title || " ";
36118 // if(this.collapsedTitleTextEl){
36119 // this.collapsedTitleTextEl.innerHTML = title;
36123 getBox : function(){
36125 // if(!this.collapsed){
36126 b = this.el.getBox(false, true);
36128 // b = this.collapsedEl.getBox(false, true);
36133 getMargins : function(){
36134 return this.margins;
36135 //return this.collapsed ? this.cmargins : this.margins;
36138 highlight : function(){
36139 this.el.addClass("x-layout-panel-dragover");
36142 unhighlight : function(){
36143 this.el.removeClass("x-layout-panel-dragover");
36146 updateBox : function(box)
36148 if (!this.bodyEl) {
36149 return; // not rendered yet..
36153 if(!this.collapsed){
36154 this.el.dom.style.left = box.x + "px";
36155 this.el.dom.style.top = box.y + "px";
36156 this.updateBody(box.width, box.height);
36158 this.collapsedEl.dom.style.left = box.x + "px";
36159 this.collapsedEl.dom.style.top = box.y + "px";
36160 this.collapsedEl.setSize(box.width, box.height);
36163 this.tabs.autoSizeTabs();
36167 updateBody : function(w, h)
36170 this.el.setWidth(w);
36171 w -= this.el.getBorderWidth("rl");
36172 if(this.config.adjustments){
36173 w += this.config.adjustments[0];
36176 if(h !== null && h > 0){
36177 this.el.setHeight(h);
36178 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36179 h -= this.el.getBorderWidth("tb");
36180 if(this.config.adjustments){
36181 h += this.config.adjustments[1];
36183 this.bodyEl.setHeight(h);
36185 h = this.tabs.syncHeight(h);
36188 if(this.panelSize){
36189 w = w !== null ? w : this.panelSize.width;
36190 h = h !== null ? h : this.panelSize.height;
36192 if(this.activePanel){
36193 var el = this.activePanel.getEl();
36194 w = w !== null ? w : el.getWidth();
36195 h = h !== null ? h : el.getHeight();
36196 this.panelSize = {width: w, height: h};
36197 this.activePanel.setSize(w, h);
36199 if(Roo.isIE && this.tabs){
36200 this.tabs.el.repaint();
36205 * Returns the container element for this region.
36206 * @return {Roo.Element}
36208 getEl : function(){
36213 * Hides this region.
36216 //if(!this.collapsed){
36217 this.el.dom.style.left = "-2000px";
36220 // this.collapsedEl.dom.style.left = "-2000px";
36221 // this.collapsedEl.hide();
36223 this.visible = false;
36224 this.fireEvent("visibilitychange", this, false);
36228 * Shows this region if it was previously hidden.
36231 //if(!this.collapsed){
36234 // this.collapsedEl.show();
36236 this.visible = true;
36237 this.fireEvent("visibilitychange", this, true);
36240 closeClicked : function(){
36241 if(this.activePanel){
36242 this.remove(this.activePanel);
36246 collapseClick : function(e){
36248 e.stopPropagation();
36251 e.stopPropagation();
36257 * Collapses this region.
36258 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36261 collapse : function(skipAnim, skipCheck = false){
36262 if(this.collapsed) {
36266 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36268 this.collapsed = true;
36270 this.split.el.hide();
36272 if(this.config.animate && skipAnim !== true){
36273 this.fireEvent("invalidated", this);
36274 this.animateCollapse();
36276 this.el.setLocation(-20000,-20000);
36278 this.collapsedEl.show();
36279 this.fireEvent("collapsed", this);
36280 this.fireEvent("invalidated", this);
36286 animateCollapse : function(){
36291 * Expands this region if it was previously collapsed.
36292 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36293 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36296 expand : function(e, skipAnim){
36298 e.stopPropagation();
36300 if(!this.collapsed || this.el.hasActiveFx()) {
36304 this.afterSlideIn();
36307 this.collapsed = false;
36308 if(this.config.animate && skipAnim !== true){
36309 this.animateExpand();
36313 this.split.el.show();
36315 this.collapsedEl.setLocation(-2000,-2000);
36316 this.collapsedEl.hide();
36317 this.fireEvent("invalidated", this);
36318 this.fireEvent("expanded", this);
36322 animateExpand : function(){
36326 initTabs : function()
36328 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36330 var ts = new Roo.bootstrap.panel.Tabs({
36331 el: this.bodyEl.dom,
36332 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36333 disableTooltips: this.config.disableTabTips,
36334 toolbar : this.config.toolbar
36337 if(this.config.hideTabs){
36338 ts.stripWrap.setDisplayed(false);
36341 ts.resizeTabs = this.config.resizeTabs === true;
36342 ts.minTabWidth = this.config.minTabWidth || 40;
36343 ts.maxTabWidth = this.config.maxTabWidth || 250;
36344 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36345 ts.monitorResize = false;
36346 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36347 ts.bodyEl.addClass('roo-layout-tabs-body');
36348 this.panels.each(this.initPanelAsTab, this);
36351 initPanelAsTab : function(panel){
36352 var ti = this.tabs.addTab(
36356 this.config.closeOnTab && panel.isClosable(),
36359 if(panel.tabTip !== undefined){
36360 ti.setTooltip(panel.tabTip);
36362 ti.on("activate", function(){
36363 this.setActivePanel(panel);
36366 if(this.config.closeOnTab){
36367 ti.on("beforeclose", function(t, e){
36369 this.remove(panel);
36373 panel.tabItem = ti;
36378 updatePanelTitle : function(panel, title)
36380 if(this.activePanel == panel){
36381 this.updateTitle(title);
36384 var ti = this.tabs.getTab(panel.getEl().id);
36386 if(panel.tabTip !== undefined){
36387 ti.setTooltip(panel.tabTip);
36392 updateTitle : function(title){
36393 if(this.titleTextEl && !this.config.title){
36394 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36398 setActivePanel : function(panel)
36400 panel = this.getPanel(panel);
36401 if(this.activePanel && this.activePanel != panel){
36402 if(this.activePanel.setActiveState(false) === false){
36406 this.activePanel = panel;
36407 panel.setActiveState(true);
36408 if(this.panelSize){
36409 panel.setSize(this.panelSize.width, this.panelSize.height);
36412 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36414 this.updateTitle(panel.getTitle());
36416 this.fireEvent("invalidated", this);
36418 this.fireEvent("panelactivated", this, panel);
36422 * Shows the specified panel.
36423 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36424 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36426 showPanel : function(panel)
36428 panel = this.getPanel(panel);
36431 var tab = this.tabs.getTab(panel.getEl().id);
36432 if(tab.isHidden()){
36433 this.tabs.unhideTab(tab.id);
36437 this.setActivePanel(panel);
36444 * Get the active panel for this region.
36445 * @return {Roo.ContentPanel} The active panel or null
36447 getActivePanel : function(){
36448 return this.activePanel;
36451 validateVisibility : function(){
36452 if(this.panels.getCount() < 1){
36453 this.updateTitle(" ");
36454 this.closeBtn.hide();
36457 if(!this.isVisible()){
36464 * Adds the passed ContentPanel(s) to this region.
36465 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36466 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36468 add : function(panel)
36470 if(arguments.length > 1){
36471 for(var i = 0, len = arguments.length; i < len; i++) {
36472 this.add(arguments[i]);
36477 // if we have not been rendered yet, then we can not really do much of this..
36478 if (!this.bodyEl) {
36479 this.unrendered_panels.push(panel);
36486 if(this.hasPanel(panel)){
36487 this.showPanel(panel);
36490 panel.setRegion(this);
36491 this.panels.add(panel);
36492 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36493 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36494 // and hide them... ???
36495 this.bodyEl.dom.appendChild(panel.getEl().dom);
36496 if(panel.background !== true){
36497 this.setActivePanel(panel);
36499 this.fireEvent("paneladded", this, panel);
36506 this.initPanelAsTab(panel);
36510 if(panel.background !== true){
36511 this.tabs.activate(panel.getEl().id);
36513 this.fireEvent("paneladded", this, panel);
36518 * Hides the tab for the specified panel.
36519 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36521 hidePanel : function(panel){
36522 if(this.tabs && (panel = this.getPanel(panel))){
36523 this.tabs.hideTab(panel.getEl().id);
36528 * Unhides the tab for a previously hidden panel.
36529 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36531 unhidePanel : function(panel){
36532 if(this.tabs && (panel = this.getPanel(panel))){
36533 this.tabs.unhideTab(panel.getEl().id);
36537 clearPanels : function(){
36538 while(this.panels.getCount() > 0){
36539 this.remove(this.panels.first());
36544 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36545 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36546 * @param {Boolean} preservePanel Overrides the config preservePanel option
36547 * @return {Roo.ContentPanel} The panel that was removed
36549 remove : function(panel, preservePanel)
36551 panel = this.getPanel(panel);
36556 this.fireEvent("beforeremove", this, panel, e);
36557 if(e.cancel === true){
36560 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36561 var panelId = panel.getId();
36562 this.panels.removeKey(panelId);
36564 document.body.appendChild(panel.getEl().dom);
36567 this.tabs.removeTab(panel.getEl().id);
36568 }else if (!preservePanel){
36569 this.bodyEl.dom.removeChild(panel.getEl().dom);
36571 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36572 var p = this.panels.first();
36573 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36574 tempEl.appendChild(p.getEl().dom);
36575 this.bodyEl.update("");
36576 this.bodyEl.dom.appendChild(p.getEl().dom);
36578 this.updateTitle(p.getTitle());
36580 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36581 this.setActivePanel(p);
36583 panel.setRegion(null);
36584 if(this.activePanel == panel){
36585 this.activePanel = null;
36587 if(this.config.autoDestroy !== false && preservePanel !== true){
36588 try{panel.destroy();}catch(e){}
36590 this.fireEvent("panelremoved", this, panel);
36595 * Returns the TabPanel component used by this region
36596 * @return {Roo.TabPanel}
36598 getTabs : function(){
36602 createTool : function(parentEl, className){
36603 var btn = Roo.DomHelper.append(parentEl, {
36605 cls: "x-layout-tools-button",
36608 cls: "roo-layout-tools-button-inner " + className,
36612 btn.addClassOnOver("roo-layout-tools-button-over");
36617 * Ext JS Library 1.1.1
36618 * Copyright(c) 2006-2007, Ext JS, LLC.
36620 * Originally Released Under LGPL - original licence link has changed is not relivant.
36623 * <script type="text/javascript">
36629 * @class Roo.SplitLayoutRegion
36630 * @extends Roo.LayoutRegion
36631 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36633 Roo.bootstrap.layout.Split = function(config){
36634 this.cursor = config.cursor;
36635 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36638 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36640 splitTip : "Drag to resize.",
36641 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36642 useSplitTips : false,
36644 applyConfig : function(config){
36645 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36648 onRender : function(ctr,pos) {
36650 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36651 if(!this.config.split){
36656 var splitEl = Roo.DomHelper.append(ctr.dom, {
36658 id: this.el.id + "-split",
36659 cls: "roo-layout-split roo-layout-split-"+this.position,
36662 /** The SplitBar for this region
36663 * @type Roo.SplitBar */
36664 // does not exist yet...
36665 Roo.log([this.position, this.orientation]);
36667 this.split = new Roo.bootstrap.SplitBar({
36668 dragElement : splitEl,
36669 resizingElement: this.el,
36670 orientation : this.orientation
36673 this.split.on("moved", this.onSplitMove, this);
36674 this.split.useShim = this.config.useShim === true;
36675 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36676 if(this.useSplitTips){
36677 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36679 //if(config.collapsible){
36680 // this.split.el.on("dblclick", this.collapse, this);
36683 if(typeof this.config.minSize != "undefined"){
36684 this.split.minSize = this.config.minSize;
36686 if(typeof this.config.maxSize != "undefined"){
36687 this.split.maxSize = this.config.maxSize;
36689 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36690 this.hideSplitter();
36695 getHMaxSize : function(){
36696 var cmax = this.config.maxSize || 10000;
36697 var center = this.mgr.getRegion("center");
36698 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36701 getVMaxSize : function(){
36702 var cmax = this.config.maxSize || 10000;
36703 var center = this.mgr.getRegion("center");
36704 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36707 onSplitMove : function(split, newSize){
36708 this.fireEvent("resized", this, newSize);
36712 * Returns the {@link Roo.SplitBar} for this region.
36713 * @return {Roo.SplitBar}
36715 getSplitBar : function(){
36720 this.hideSplitter();
36721 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36724 hideSplitter : function(){
36726 this.split.el.setLocation(-2000,-2000);
36727 this.split.el.hide();
36733 this.split.el.show();
36735 Roo.bootstrap.layout.Split.superclass.show.call(this);
36738 beforeSlide: function(){
36739 if(Roo.isGecko){// firefox overflow auto bug workaround
36740 this.bodyEl.clip();
36742 this.tabs.bodyEl.clip();
36744 if(this.activePanel){
36745 this.activePanel.getEl().clip();
36747 if(this.activePanel.beforeSlide){
36748 this.activePanel.beforeSlide();
36754 afterSlide : function(){
36755 if(Roo.isGecko){// firefox overflow auto bug workaround
36756 this.bodyEl.unclip();
36758 this.tabs.bodyEl.unclip();
36760 if(this.activePanel){
36761 this.activePanel.getEl().unclip();
36762 if(this.activePanel.afterSlide){
36763 this.activePanel.afterSlide();
36769 initAutoHide : function(){
36770 if(this.autoHide !== false){
36771 if(!this.autoHideHd){
36772 var st = new Roo.util.DelayedTask(this.slideIn, this);
36773 this.autoHideHd = {
36774 "mouseout": function(e){
36775 if(!e.within(this.el, true)){
36779 "mouseover" : function(e){
36785 this.el.on(this.autoHideHd);
36789 clearAutoHide : function(){
36790 if(this.autoHide !== false){
36791 this.el.un("mouseout", this.autoHideHd.mouseout);
36792 this.el.un("mouseover", this.autoHideHd.mouseover);
36796 clearMonitor : function(){
36797 Roo.get(document).un("click", this.slideInIf, this);
36800 // these names are backwards but not changed for compat
36801 slideOut : function(){
36802 if(this.isSlid || this.el.hasActiveFx()){
36805 this.isSlid = true;
36806 if(this.collapseBtn){
36807 this.collapseBtn.hide();
36809 this.closeBtnState = this.closeBtn.getStyle('display');
36810 this.closeBtn.hide();
36812 this.stickBtn.show();
36815 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36816 this.beforeSlide();
36817 this.el.setStyle("z-index", 10001);
36818 this.el.slideIn(this.getSlideAnchor(), {
36819 callback: function(){
36821 this.initAutoHide();
36822 Roo.get(document).on("click", this.slideInIf, this);
36823 this.fireEvent("slideshow", this);
36830 afterSlideIn : function(){
36831 this.clearAutoHide();
36832 this.isSlid = false;
36833 this.clearMonitor();
36834 this.el.setStyle("z-index", "");
36835 if(this.collapseBtn){
36836 this.collapseBtn.show();
36838 this.closeBtn.setStyle('display', this.closeBtnState);
36840 this.stickBtn.hide();
36842 this.fireEvent("slidehide", this);
36845 slideIn : function(cb){
36846 if(!this.isSlid || this.el.hasActiveFx()){
36850 this.isSlid = false;
36851 this.beforeSlide();
36852 this.el.slideOut(this.getSlideAnchor(), {
36853 callback: function(){
36854 this.el.setLeftTop(-10000, -10000);
36856 this.afterSlideIn();
36864 slideInIf : function(e){
36865 if(!e.within(this.el)){
36870 animateCollapse : function(){
36871 this.beforeSlide();
36872 this.el.setStyle("z-index", 20000);
36873 var anchor = this.getSlideAnchor();
36874 this.el.slideOut(anchor, {
36875 callback : function(){
36876 this.el.setStyle("z-index", "");
36877 this.collapsedEl.slideIn(anchor, {duration:.3});
36879 this.el.setLocation(-10000,-10000);
36881 this.fireEvent("collapsed", this);
36888 animateExpand : function(){
36889 this.beforeSlide();
36890 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36891 this.el.setStyle("z-index", 20000);
36892 this.collapsedEl.hide({
36895 this.el.slideIn(this.getSlideAnchor(), {
36896 callback : function(){
36897 this.el.setStyle("z-index", "");
36900 this.split.el.show();
36902 this.fireEvent("invalidated", this);
36903 this.fireEvent("expanded", this);
36931 getAnchor : function(){
36932 return this.anchors[this.position];
36935 getCollapseAnchor : function(){
36936 return this.canchors[this.position];
36939 getSlideAnchor : function(){
36940 return this.sanchors[this.position];
36943 getAlignAdj : function(){
36944 var cm = this.cmargins;
36945 switch(this.position){
36961 getExpandAdj : function(){
36962 var c = this.collapsedEl, cm = this.cmargins;
36963 switch(this.position){
36965 return [-(cm.right+c.getWidth()+cm.left), 0];
36968 return [cm.right+c.getWidth()+cm.left, 0];
36971 return [0, -(cm.top+cm.bottom+c.getHeight())];
36974 return [0, cm.top+cm.bottom+c.getHeight()];
36980 * Ext JS Library 1.1.1
36981 * Copyright(c) 2006-2007, Ext JS, LLC.
36983 * Originally Released Under LGPL - original licence link has changed is not relivant.
36986 * <script type="text/javascript">
36989 * These classes are private internal classes
36991 Roo.bootstrap.layout.Center = function(config){
36992 config.region = "center";
36993 Roo.bootstrap.layout.Region.call(this, config);
36994 this.visible = true;
36995 this.minWidth = config.minWidth || 20;
36996 this.minHeight = config.minHeight || 20;
36999 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37001 // center panel can't be hidden
37005 // center panel can't be hidden
37008 getMinWidth: function(){
37009 return this.minWidth;
37012 getMinHeight: function(){
37013 return this.minHeight;
37026 Roo.bootstrap.layout.North = function(config)
37028 config.region = 'north';
37029 config.cursor = 'n-resize';
37031 Roo.bootstrap.layout.Split.call(this, config);
37035 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37036 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37037 this.split.el.addClass("roo-layout-split-v");
37039 var size = config.initialSize || config.height;
37040 if(typeof size != "undefined"){
37041 this.el.setHeight(size);
37044 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37046 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37050 getBox : function(){
37051 if(this.collapsed){
37052 return this.collapsedEl.getBox();
37054 var box = this.el.getBox();
37056 box.height += this.split.el.getHeight();
37061 updateBox : function(box){
37062 if(this.split && !this.collapsed){
37063 box.height -= this.split.el.getHeight();
37064 this.split.el.setLeft(box.x);
37065 this.split.el.setTop(box.y+box.height);
37066 this.split.el.setWidth(box.width);
37068 if(this.collapsed){
37069 this.updateBody(box.width, null);
37071 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37079 Roo.bootstrap.layout.South = function(config){
37080 config.region = 'south';
37081 config.cursor = 's-resize';
37082 Roo.bootstrap.layout.Split.call(this, config);
37084 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37085 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37086 this.split.el.addClass("roo-layout-split-v");
37088 var size = config.initialSize || config.height;
37089 if(typeof size != "undefined"){
37090 this.el.setHeight(size);
37094 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37095 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37096 getBox : function(){
37097 if(this.collapsed){
37098 return this.collapsedEl.getBox();
37100 var box = this.el.getBox();
37102 var sh = this.split.el.getHeight();
37109 updateBox : function(box){
37110 if(this.split && !this.collapsed){
37111 var sh = this.split.el.getHeight();
37114 this.split.el.setLeft(box.x);
37115 this.split.el.setTop(box.y-sh);
37116 this.split.el.setWidth(box.width);
37118 if(this.collapsed){
37119 this.updateBody(box.width, null);
37121 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37125 Roo.bootstrap.layout.East = function(config){
37126 config.region = "east";
37127 config.cursor = "e-resize";
37128 Roo.bootstrap.layout.Split.call(this, config);
37130 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37131 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37132 this.split.el.addClass("roo-layout-split-h");
37134 var size = config.initialSize || config.width;
37135 if(typeof size != "undefined"){
37136 this.el.setWidth(size);
37139 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37140 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37141 getBox : function(){
37142 if(this.collapsed){
37143 return this.collapsedEl.getBox();
37145 var box = this.el.getBox();
37147 var sw = this.split.el.getWidth();
37154 updateBox : function(box){
37155 if(this.split && !this.collapsed){
37156 var sw = this.split.el.getWidth();
37158 this.split.el.setLeft(box.x);
37159 this.split.el.setTop(box.y);
37160 this.split.el.setHeight(box.height);
37163 if(this.collapsed){
37164 this.updateBody(null, box.height);
37166 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37170 Roo.bootstrap.layout.West = function(config){
37171 config.region = "west";
37172 config.cursor = "w-resize";
37174 Roo.bootstrap.layout.Split.call(this, config);
37176 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37177 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37178 this.split.el.addClass("roo-layout-split-h");
37182 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37183 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37185 onRender: function(ctr, pos)
37187 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37188 var size = this.config.initialSize || this.config.width;
37189 if(typeof size != "undefined"){
37190 this.el.setWidth(size);
37194 getBox : function(){
37195 if(this.collapsed){
37196 return this.collapsedEl.getBox();
37198 var box = this.el.getBox();
37200 box.width += this.split.el.getWidth();
37205 updateBox : function(box){
37206 if(this.split && !this.collapsed){
37207 var sw = this.split.el.getWidth();
37209 this.split.el.setLeft(box.x+box.width);
37210 this.split.el.setTop(box.y);
37211 this.split.el.setHeight(box.height);
37213 if(this.collapsed){
37214 this.updateBody(null, box.height);
37216 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37219 Roo.namespace("Roo.bootstrap.panel");/*
37221 * Ext JS Library 1.1.1
37222 * Copyright(c) 2006-2007, Ext JS, LLC.
37224 * Originally Released Under LGPL - original licence link has changed is not relivant.
37227 * <script type="text/javascript">
37230 * @class Roo.ContentPanel
37231 * @extends Roo.util.Observable
37232 * A basic ContentPanel element.
37233 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37234 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37235 * @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
37236 * @cfg {Boolean} closable True if the panel can be closed/removed
37237 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37238 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37239 * @cfg {Toolbar} toolbar A toolbar for this panel
37240 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37241 * @cfg {String} title The title for this panel
37242 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37243 * @cfg {String} url Calls {@link #setUrl} with this value
37244 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37245 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37246 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37247 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37248 * @cfg {Boolean} badges render the badges
37251 * Create a new ContentPanel.
37252 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37253 * @param {String/Object} config A string to set only the title or a config object
37254 * @param {String} content (optional) Set the HTML content for this panel
37255 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37257 Roo.bootstrap.panel.Content = function( config){
37259 this.tpl = config.tpl || false;
37261 var el = config.el;
37262 var content = config.content;
37264 if(config.autoCreate){ // xtype is available if this is called from factory
37267 this.el = Roo.get(el);
37268 if(!this.el && config && config.autoCreate){
37269 if(typeof config.autoCreate == "object"){
37270 if(!config.autoCreate.id){
37271 config.autoCreate.id = config.id||el;
37273 this.el = Roo.DomHelper.append(document.body,
37274 config.autoCreate, true);
37276 var elcfg = { tag: "div",
37277 cls: "roo-layout-inactive-content",
37281 elcfg.html = config.html;
37285 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37288 this.closable = false;
37289 this.loaded = false;
37290 this.active = false;
37293 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37295 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37297 this.wrapEl = this.el; //this.el.wrap();
37299 if (config.toolbar.items) {
37300 ti = config.toolbar.items ;
37301 delete config.toolbar.items ;
37305 this.toolbar.render(this.wrapEl, 'before');
37306 for(var i =0;i < ti.length;i++) {
37307 // Roo.log(['add child', items[i]]);
37308 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37310 this.toolbar.items = nitems;
37311 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37312 delete config.toolbar;
37316 // xtype created footer. - not sure if will work as we normally have to render first..
37317 if (this.footer && !this.footer.el && this.footer.xtype) {
37318 if (!this.wrapEl) {
37319 this.wrapEl = this.el.wrap();
37322 this.footer.container = this.wrapEl.createChild();
37324 this.footer = Roo.factory(this.footer, Roo);
37329 if(typeof config == "string"){
37330 this.title = config;
37332 Roo.apply(this, config);
37336 this.resizeEl = Roo.get(this.resizeEl, true);
37338 this.resizeEl = this.el;
37340 // handle view.xtype
37348 * Fires when this panel is activated.
37349 * @param {Roo.ContentPanel} this
37353 * @event deactivate
37354 * Fires when this panel is activated.
37355 * @param {Roo.ContentPanel} this
37357 "deactivate" : true,
37361 * Fires when this panel is resized if fitToFrame is true.
37362 * @param {Roo.ContentPanel} this
37363 * @param {Number} width The width after any component adjustments
37364 * @param {Number} height The height after any component adjustments
37370 * Fires when this tab is created
37371 * @param {Roo.ContentPanel} this
37382 if(this.autoScroll){
37383 this.resizeEl.setStyle("overflow", "auto");
37385 // fix randome scrolling
37386 //this.el.on('scroll', function() {
37387 // Roo.log('fix random scolling');
37388 // this.scrollTo('top',0);
37391 content = content || this.content;
37393 this.setContent(content);
37395 if(config && config.url){
37396 this.setUrl(this.url, this.params, this.loadOnce);
37401 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37403 if (this.view && typeof(this.view.xtype) != 'undefined') {
37404 this.view.el = this.el.appendChild(document.createElement("div"));
37405 this.view = Roo.factory(this.view);
37406 this.view.render && this.view.render(false, '');
37410 this.fireEvent('render', this);
37413 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37417 setRegion : function(region){
37418 this.region = region;
37419 this.setActiveClass(region && !this.background);
37423 setActiveClass: function(state)
37426 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37427 this.el.setStyle('position','relative');
37429 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37430 this.el.setStyle('position', 'absolute');
37435 * Returns the toolbar for this Panel if one was configured.
37436 * @return {Roo.Toolbar}
37438 getToolbar : function(){
37439 return this.toolbar;
37442 setActiveState : function(active)
37444 this.active = active;
37445 this.setActiveClass(active);
37447 if(this.fireEvent("deactivate", this) === false){
37452 this.fireEvent("activate", this);
37456 * Updates this panel's element
37457 * @param {String} content The new content
37458 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37460 setContent : function(content, loadScripts){
37461 this.el.update(content, loadScripts);
37464 ignoreResize : function(w, h){
37465 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37468 this.lastSize = {width: w, height: h};
37473 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37474 * @return {Roo.UpdateManager} The UpdateManager
37476 getUpdateManager : function(){
37477 return this.el.getUpdateManager();
37480 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37481 * @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:
37484 url: "your-url.php",
37485 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37486 callback: yourFunction,
37487 scope: yourObject, //(optional scope)
37490 text: "Loading...",
37495 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37496 * 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.
37497 * @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}
37498 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37499 * @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.
37500 * @return {Roo.ContentPanel} this
37503 var um = this.el.getUpdateManager();
37504 um.update.apply(um, arguments);
37510 * 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.
37511 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37512 * @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)
37513 * @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)
37514 * @return {Roo.UpdateManager} The UpdateManager
37516 setUrl : function(url, params, loadOnce){
37517 if(this.refreshDelegate){
37518 this.removeListener("activate", this.refreshDelegate);
37520 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37521 this.on("activate", this.refreshDelegate);
37522 return this.el.getUpdateManager();
37525 _handleRefresh : function(url, params, loadOnce){
37526 if(!loadOnce || !this.loaded){
37527 var updater = this.el.getUpdateManager();
37528 updater.update(url, params, this._setLoaded.createDelegate(this));
37532 _setLoaded : function(){
37533 this.loaded = true;
37537 * Returns this panel's id
37540 getId : function(){
37545 * Returns this panel's element - used by regiosn to add.
37546 * @return {Roo.Element}
37548 getEl : function(){
37549 return this.wrapEl || this.el;
37554 adjustForComponents : function(width, height)
37556 //Roo.log('adjustForComponents ');
37557 if(this.resizeEl != this.el){
37558 width -= this.el.getFrameWidth('lr');
37559 height -= this.el.getFrameWidth('tb');
37562 var te = this.toolbar.getEl();
37563 te.setWidth(width);
37564 height -= te.getHeight();
37567 var te = this.footer.getEl();
37568 te.setWidth(width);
37569 height -= te.getHeight();
37573 if(this.adjustments){
37574 width += this.adjustments[0];
37575 height += this.adjustments[1];
37577 return {"width": width, "height": height};
37580 setSize : function(width, height){
37581 if(this.fitToFrame && !this.ignoreResize(width, height)){
37582 if(this.fitContainer && this.resizeEl != this.el){
37583 this.el.setSize(width, height);
37585 var size = this.adjustForComponents(width, height);
37586 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37587 this.fireEvent('resize', this, size.width, size.height);
37592 * Returns this panel's title
37595 getTitle : function(){
37597 if (typeof(this.title) != 'object') {
37602 for (var k in this.title) {
37603 if (!this.title.hasOwnProperty(k)) {
37607 if (k.indexOf('-') >= 0) {
37608 var s = k.split('-');
37609 for (var i = 0; i<s.length; i++) {
37610 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37613 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37620 * Set this panel's title
37621 * @param {String} title
37623 setTitle : function(title){
37624 this.title = title;
37626 this.region.updatePanelTitle(this, title);
37631 * Returns true is this panel was configured to be closable
37632 * @return {Boolean}
37634 isClosable : function(){
37635 return this.closable;
37638 beforeSlide : function(){
37640 this.resizeEl.clip();
37643 afterSlide : function(){
37645 this.resizeEl.unclip();
37649 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37650 * Will fail silently if the {@link #setUrl} method has not been called.
37651 * This does not activate the panel, just updates its content.
37653 refresh : function(){
37654 if(this.refreshDelegate){
37655 this.loaded = false;
37656 this.refreshDelegate();
37661 * Destroys this panel
37663 destroy : function(){
37664 this.el.removeAllListeners();
37665 var tempEl = document.createElement("span");
37666 tempEl.appendChild(this.el.dom);
37667 tempEl.innerHTML = "";
37673 * form - if the content panel contains a form - this is a reference to it.
37674 * @type {Roo.form.Form}
37678 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37679 * This contains a reference to it.
37685 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37695 * @param {Object} cfg Xtype definition of item to add.
37699 getChildContainer: function () {
37700 return this.getEl();
37705 var ret = new Roo.factory(cfg);
37710 if (cfg.xtype.match(/^Form$/)) {
37713 //if (this.footer) {
37714 // el = this.footer.container.insertSibling(false, 'before');
37716 el = this.el.createChild();
37719 this.form = new Roo.form.Form(cfg);
37722 if ( this.form.allItems.length) {
37723 this.form.render(el.dom);
37727 // should only have one of theses..
37728 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37729 // views.. should not be just added - used named prop 'view''
37731 cfg.el = this.el.appendChild(document.createElement("div"));
37734 var ret = new Roo.factory(cfg);
37736 ret.render && ret.render(false, ''); // render blank..
37746 * @class Roo.bootstrap.panel.Grid
37747 * @extends Roo.bootstrap.panel.Content
37749 * Create a new GridPanel.
37750 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37751 * @param {Object} config A the config object
37757 Roo.bootstrap.panel.Grid = function(config)
37761 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37762 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37764 config.el = this.wrapper;
37765 //this.el = this.wrapper;
37767 if (config.container) {
37768 // ctor'ed from a Border/panel.grid
37771 this.wrapper.setStyle("overflow", "hidden");
37772 this.wrapper.addClass('roo-grid-container');
37777 if(config.toolbar){
37778 var tool_el = this.wrapper.createChild();
37779 this.toolbar = Roo.factory(config.toolbar);
37781 if (config.toolbar.items) {
37782 ti = config.toolbar.items ;
37783 delete config.toolbar.items ;
37787 this.toolbar.render(tool_el);
37788 for(var i =0;i < ti.length;i++) {
37789 // Roo.log(['add child', items[i]]);
37790 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37792 this.toolbar.items = nitems;
37794 delete config.toolbar;
37797 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37798 config.grid.scrollBody = true;;
37799 config.grid.monitorWindowResize = false; // turn off autosizing
37800 config.grid.autoHeight = false;
37801 config.grid.autoWidth = false;
37803 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37805 if (config.background) {
37806 // render grid on panel activation (if panel background)
37807 this.on('activate', function(gp) {
37808 if (!gp.grid.rendered) {
37809 gp.grid.render(this.wrapper);
37810 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37815 this.grid.render(this.wrapper);
37816 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37819 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37820 // ??? needed ??? config.el = this.wrapper;
37825 // xtype created footer. - not sure if will work as we normally have to render first..
37826 if (this.footer && !this.footer.el && this.footer.xtype) {
37828 var ctr = this.grid.getView().getFooterPanel(true);
37829 this.footer.dataSource = this.grid.dataSource;
37830 this.footer = Roo.factory(this.footer, Roo);
37831 this.footer.render(ctr);
37841 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37842 getId : function(){
37843 return this.grid.id;
37847 * Returns the grid for this panel
37848 * @return {Roo.bootstrap.Table}
37850 getGrid : function(){
37854 setSize : function(width, height){
37855 if(!this.ignoreResize(width, height)){
37856 var grid = this.grid;
37857 var size = this.adjustForComponents(width, height);
37858 var gridel = grid.getGridEl();
37859 gridel.setSize(size.width, size.height);
37861 var thd = grid.getGridEl().select('thead',true).first();
37862 var tbd = grid.getGridEl().select('tbody', true).first();
37864 tbd.setSize(width, height - thd.getHeight());
37873 beforeSlide : function(){
37874 this.grid.getView().scroller.clip();
37877 afterSlide : function(){
37878 this.grid.getView().scroller.unclip();
37881 destroy : function(){
37882 this.grid.destroy();
37884 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37889 * @class Roo.bootstrap.panel.Nest
37890 * @extends Roo.bootstrap.panel.Content
37892 * Create a new Panel, that can contain a layout.Border.
37895 * @param {Roo.BorderLayout} layout The layout for this panel
37896 * @param {String/Object} config A string to set only the title or a config object
37898 Roo.bootstrap.panel.Nest = function(config)
37900 // construct with only one argument..
37901 /* FIXME - implement nicer consturctors
37902 if (layout.layout) {
37904 layout = config.layout;
37905 delete config.layout;
37907 if (layout.xtype && !layout.getEl) {
37908 // then layout needs constructing..
37909 layout = Roo.factory(layout, Roo);
37913 config.el = config.layout.getEl();
37915 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37917 config.layout.monitorWindowResize = false; // turn off autosizing
37918 this.layout = config.layout;
37919 this.layout.getEl().addClass("roo-layout-nested-layout");
37926 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37928 setSize : function(width, height){
37929 if(!this.ignoreResize(width, height)){
37930 var size = this.adjustForComponents(width, height);
37931 var el = this.layout.getEl();
37932 if (size.height < 1) {
37933 el.setWidth(size.width);
37935 el.setSize(size.width, size.height);
37937 var touch = el.dom.offsetWidth;
37938 this.layout.layout();
37939 // ie requires a double layout on the first pass
37940 if(Roo.isIE && !this.initialized){
37941 this.initialized = true;
37942 this.layout.layout();
37947 // activate all subpanels if not currently active..
37949 setActiveState : function(active){
37950 this.active = active;
37951 this.setActiveClass(active);
37954 this.fireEvent("deactivate", this);
37958 this.fireEvent("activate", this);
37959 // not sure if this should happen before or after..
37960 if (!this.layout) {
37961 return; // should not happen..
37964 for (var r in this.layout.regions) {
37965 reg = this.layout.getRegion(r);
37966 if (reg.getActivePanel()) {
37967 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37968 reg.setActivePanel(reg.getActivePanel());
37971 if (!reg.panels.length) {
37974 reg.showPanel(reg.getPanel(0));
37983 * Returns the nested BorderLayout for this panel
37984 * @return {Roo.BorderLayout}
37986 getLayout : function(){
37987 return this.layout;
37991 * Adds a xtype elements to the layout of the nested panel
37995 xtype : 'ContentPanel',
38002 xtype : 'NestedLayoutPanel',
38008 items : [ ... list of content panels or nested layout panels.. ]
38012 * @param {Object} cfg Xtype definition of item to add.
38014 addxtype : function(cfg) {
38015 return this.layout.addxtype(cfg);
38020 * Ext JS Library 1.1.1
38021 * Copyright(c) 2006-2007, Ext JS, LLC.
38023 * Originally Released Under LGPL - original licence link has changed is not relivant.
38026 * <script type="text/javascript">
38029 * @class Roo.TabPanel
38030 * @extends Roo.util.Observable
38031 * A lightweight tab container.
38035 // basic tabs 1, built from existing content
38036 var tabs = new Roo.TabPanel("tabs1");
38037 tabs.addTab("script", "View Script");
38038 tabs.addTab("markup", "View Markup");
38039 tabs.activate("script");
38041 // more advanced tabs, built from javascript
38042 var jtabs = new Roo.TabPanel("jtabs");
38043 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38045 // set up the UpdateManager
38046 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38047 var updater = tab2.getUpdateManager();
38048 updater.setDefaultUrl("ajax1.htm");
38049 tab2.on('activate', updater.refresh, updater, true);
38051 // Use setUrl for Ajax loading
38052 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38053 tab3.setUrl("ajax2.htm", null, true);
38056 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38059 jtabs.activate("jtabs-1");
38062 * Create a new TabPanel.
38063 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38064 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38066 Roo.bootstrap.panel.Tabs = function(config){
38068 * The container element for this TabPanel.
38069 * @type Roo.Element
38071 this.el = Roo.get(config.el);
38074 if(typeof config == "boolean"){
38075 this.tabPosition = config ? "bottom" : "top";
38077 Roo.apply(this, config);
38081 if(this.tabPosition == "bottom"){
38082 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38083 this.el.addClass("roo-tabs-bottom");
38085 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38086 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38087 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38088 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38090 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38092 if(this.tabPosition != "bottom"){
38093 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38094 * @type Roo.Element
38096 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38097 this.el.addClass("roo-tabs-top");
38101 this.bodyEl.setStyle("position", "relative");
38103 this.active = null;
38104 this.activateDelegate = this.activate.createDelegate(this);
38109 * Fires when the active tab changes
38110 * @param {Roo.TabPanel} this
38111 * @param {Roo.TabPanelItem} activePanel The new active tab
38115 * @event beforetabchange
38116 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38117 * @param {Roo.TabPanel} this
38118 * @param {Object} e Set cancel to true on this object to cancel the tab change
38119 * @param {Roo.TabPanelItem} tab The tab being changed to
38121 "beforetabchange" : true
38124 Roo.EventManager.onWindowResize(this.onResize, this);
38125 this.cpad = this.el.getPadding("lr");
38126 this.hiddenCount = 0;
38129 // toolbar on the tabbar support...
38130 if (this.toolbar) {
38131 alert("no toolbar support yet");
38132 this.toolbar = false;
38134 var tcfg = this.toolbar;
38135 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38136 this.toolbar = new Roo.Toolbar(tcfg);
38137 if (Roo.isSafari) {
38138 var tbl = tcfg.container.child('table', true);
38139 tbl.setAttribute('width', '100%');
38147 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38150 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38152 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38154 tabPosition : "top",
38156 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38158 currentTabWidth : 0,
38160 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38164 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38168 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38170 preferredTabWidth : 175,
38172 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38174 resizeTabs : false,
38176 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38178 monitorResize : true,
38180 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38185 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38186 * @param {String} id The id of the div to use <b>or create</b>
38187 * @param {String} text The text for the tab
38188 * @param {String} content (optional) Content to put in the TabPanelItem body
38189 * @param {Boolean} closable (optional) True to create a close icon on the tab
38190 * @return {Roo.TabPanelItem} The created TabPanelItem
38192 addTab : function(id, text, content, closable, tpl)
38194 var item = new Roo.bootstrap.panel.TabItem({
38198 closable : closable,
38201 this.addTabItem(item);
38203 item.setContent(content);
38209 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38210 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38211 * @return {Roo.TabPanelItem}
38213 getTab : function(id){
38214 return this.items[id];
38218 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38219 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38221 hideTab : function(id){
38222 var t = this.items[id];
38225 this.hiddenCount++;
38226 this.autoSizeTabs();
38231 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38232 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38234 unhideTab : function(id){
38235 var t = this.items[id];
38237 t.setHidden(false);
38238 this.hiddenCount--;
38239 this.autoSizeTabs();
38244 * Adds an existing {@link Roo.TabPanelItem}.
38245 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38247 addTabItem : function(item)
38249 this.items[item.id] = item;
38250 this.items.push(item);
38251 this.autoSizeTabs();
38252 // if(this.resizeTabs){
38253 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38254 // this.autoSizeTabs();
38256 // item.autoSize();
38261 * Removes a {@link Roo.TabPanelItem}.
38262 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38264 removeTab : function(id){
38265 var items = this.items;
38266 var tab = items[id];
38267 if(!tab) { return; }
38268 var index = items.indexOf(tab);
38269 if(this.active == tab && items.length > 1){
38270 var newTab = this.getNextAvailable(index);
38275 this.stripEl.dom.removeChild(tab.pnode.dom);
38276 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38277 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38279 items.splice(index, 1);
38280 delete this.items[tab.id];
38281 tab.fireEvent("close", tab);
38282 tab.purgeListeners();
38283 this.autoSizeTabs();
38286 getNextAvailable : function(start){
38287 var items = this.items;
38289 // look for a next tab that will slide over to
38290 // replace the one being removed
38291 while(index < items.length){
38292 var item = items[++index];
38293 if(item && !item.isHidden()){
38297 // if one isn't found select the previous tab (on the left)
38300 var item = items[--index];
38301 if(item && !item.isHidden()){
38309 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38310 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38312 disableTab : function(id){
38313 var tab = this.items[id];
38314 if(tab && this.active != tab){
38320 * Enables a {@link Roo.TabPanelItem} that is disabled.
38321 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38323 enableTab : function(id){
38324 var tab = this.items[id];
38329 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38330 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38331 * @return {Roo.TabPanelItem} The TabPanelItem.
38333 activate : function(id)
38335 var tab = this.items[id];
38339 if(tab == this.active || tab.disabled){
38343 this.fireEvent("beforetabchange", this, e, tab);
38344 if(e.cancel !== true && !tab.disabled){
38346 this.active.hide();
38348 this.active = this.items[id];
38349 this.active.show();
38350 this.fireEvent("tabchange", this, this.active);
38356 * Gets the active {@link Roo.TabPanelItem}.
38357 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38359 getActiveTab : function(){
38360 return this.active;
38364 * Updates the tab body element to fit the height of the container element
38365 * for overflow scrolling
38366 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38368 syncHeight : function(targetHeight){
38369 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38370 var bm = this.bodyEl.getMargins();
38371 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38372 this.bodyEl.setHeight(newHeight);
38376 onResize : function(){
38377 if(this.monitorResize){
38378 this.autoSizeTabs();
38383 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38385 beginUpdate : function(){
38386 this.updating = true;
38390 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38392 endUpdate : function(){
38393 this.updating = false;
38394 this.autoSizeTabs();
38398 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38400 autoSizeTabs : function()
38402 var count = this.items.length;
38403 var vcount = count - this.hiddenCount;
38406 this.stripEl.hide();
38408 this.stripEl.show();
38411 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38416 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38417 var availWidth = Math.floor(w / vcount);
38418 var b = this.stripBody;
38419 if(b.getWidth() > w){
38420 var tabs = this.items;
38421 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38422 if(availWidth < this.minTabWidth){
38423 /*if(!this.sleft){ // incomplete scrolling code
38424 this.createScrollButtons();
38427 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38430 if(this.currentTabWidth < this.preferredTabWidth){
38431 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38437 * Returns the number of tabs in this TabPanel.
38440 getCount : function(){
38441 return this.items.length;
38445 * Resizes all the tabs to the passed width
38446 * @param {Number} The new width
38448 setTabWidth : function(width){
38449 this.currentTabWidth = width;
38450 for(var i = 0, len = this.items.length; i < len; i++) {
38451 if(!this.items[i].isHidden()) {
38452 this.items[i].setWidth(width);
38458 * Destroys this TabPanel
38459 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38461 destroy : function(removeEl){
38462 Roo.EventManager.removeResizeListener(this.onResize, this);
38463 for(var i = 0, len = this.items.length; i < len; i++){
38464 this.items[i].purgeListeners();
38466 if(removeEl === true){
38467 this.el.update("");
38472 createStrip : function(container)
38474 var strip = document.createElement("nav");
38475 strip.className = Roo.bootstrap.version == 4 ?
38476 "navbar-light bg-light" :
38477 "navbar navbar-default"; //"x-tabs-wrap";
38478 container.appendChild(strip);
38482 createStripList : function(strip)
38484 // div wrapper for retard IE
38485 // returns the "tr" element.
38486 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38487 //'<div class="x-tabs-strip-wrap">'+
38488 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38489 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38490 return strip.firstChild; //.firstChild.firstChild.firstChild;
38492 createBody : function(container)
38494 var body = document.createElement("div");
38495 Roo.id(body, "tab-body");
38496 //Roo.fly(body).addClass("x-tabs-body");
38497 Roo.fly(body).addClass("tab-content");
38498 container.appendChild(body);
38501 createItemBody :function(bodyEl, id){
38502 var body = Roo.getDom(id);
38504 body = document.createElement("div");
38507 //Roo.fly(body).addClass("x-tabs-item-body");
38508 Roo.fly(body).addClass("tab-pane");
38509 bodyEl.insertBefore(body, bodyEl.firstChild);
38513 createStripElements : function(stripEl, text, closable, tpl)
38515 var td = document.createElement("li"); // was td..
38516 td.className = 'nav-item';
38518 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38521 stripEl.appendChild(td);
38523 td.className = "x-tabs-closable";
38524 if(!this.closeTpl){
38525 this.closeTpl = new Roo.Template(
38526 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38527 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38528 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38531 var el = this.closeTpl.overwrite(td, {"text": text});
38532 var close = el.getElementsByTagName("div")[0];
38533 var inner = el.getElementsByTagName("em")[0];
38534 return {"el": el, "close": close, "inner": inner};
38537 // not sure what this is..
38538 // if(!this.tabTpl){
38539 //this.tabTpl = new Roo.Template(
38540 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38541 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38543 // this.tabTpl = new Roo.Template(
38544 // '<a href="#">' +
38545 // '<span unselectable="on"' +
38546 // (this.disableTooltips ? '' : ' title="{text}"') +
38547 // ' >{text}</span></a>'
38553 var template = tpl || this.tabTpl || false;
38556 template = new Roo.Template(
38557 Roo.bootstrap.version == 4 ?
38559 '<a class="nav-link" href="#" unselectable="on"' +
38560 (this.disableTooltips ? '' : ' title="{text}"') +
38563 '<a class="nav-link" href="#">' +
38564 '<span unselectable="on"' +
38565 (this.disableTooltips ? '' : ' title="{text}"') +
38566 ' >{text}</span></a>'
38571 switch (typeof(template)) {
38575 template = new Roo.Template(template);
38581 var el = template.overwrite(td, {"text": text});
38583 var inner = el.getElementsByTagName("span")[0];
38585 return {"el": el, "inner": inner};
38593 * @class Roo.TabPanelItem
38594 * @extends Roo.util.Observable
38595 * Represents an individual item (tab plus body) in a TabPanel.
38596 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38597 * @param {String} id The id of this TabPanelItem
38598 * @param {String} text The text for the tab of this TabPanelItem
38599 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38601 Roo.bootstrap.panel.TabItem = function(config){
38603 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38604 * @type Roo.TabPanel
38606 this.tabPanel = config.panel;
38608 * The id for this TabPanelItem
38611 this.id = config.id;
38613 this.disabled = false;
38615 this.text = config.text;
38617 this.loaded = false;
38618 this.closable = config.closable;
38621 * The body element for this TabPanelItem.
38622 * @type Roo.Element
38624 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38625 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38626 this.bodyEl.setStyle("display", "block");
38627 this.bodyEl.setStyle("zoom", "1");
38628 //this.hideAction();
38630 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38632 this.el = Roo.get(els.el);
38633 this.inner = Roo.get(els.inner, true);
38634 this.textEl = Roo.bootstrap.version == 4 ?
38635 this.el : Roo.get(this.el.dom.firstChild, true);
38637 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38638 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38641 // this.el.on("mousedown", this.onTabMouseDown, this);
38642 this.el.on("click", this.onTabClick, this);
38644 if(config.closable){
38645 var c = Roo.get(els.close, true);
38646 c.dom.title = this.closeText;
38647 c.addClassOnOver("close-over");
38648 c.on("click", this.closeClick, this);
38654 * Fires when this tab becomes the active tab.
38655 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38656 * @param {Roo.TabPanelItem} this
38660 * @event beforeclose
38661 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38662 * @param {Roo.TabPanelItem} this
38663 * @param {Object} e Set cancel to true on this object to cancel the close.
38665 "beforeclose": true,
38668 * Fires when this tab is closed.
38669 * @param {Roo.TabPanelItem} this
38673 * @event deactivate
38674 * Fires when this tab is no longer the active tab.
38675 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38676 * @param {Roo.TabPanelItem} this
38678 "deactivate" : true
38680 this.hidden = false;
38682 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38685 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38687 purgeListeners : function(){
38688 Roo.util.Observable.prototype.purgeListeners.call(this);
38689 this.el.removeAllListeners();
38692 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38695 this.status_node.addClass("active");
38698 this.tabPanel.stripWrap.repaint();
38700 this.fireEvent("activate", this.tabPanel, this);
38704 * Returns true if this tab is the active tab.
38705 * @return {Boolean}
38707 isActive : function(){
38708 return this.tabPanel.getActiveTab() == this;
38712 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38715 this.status_node.removeClass("active");
38717 this.fireEvent("deactivate", this.tabPanel, this);
38720 hideAction : function(){
38721 this.bodyEl.hide();
38722 this.bodyEl.setStyle("position", "absolute");
38723 this.bodyEl.setLeft("-20000px");
38724 this.bodyEl.setTop("-20000px");
38727 showAction : function(){
38728 this.bodyEl.setStyle("position", "relative");
38729 this.bodyEl.setTop("");
38730 this.bodyEl.setLeft("");
38731 this.bodyEl.show();
38735 * Set the tooltip for the tab.
38736 * @param {String} tooltip The tab's tooltip
38738 setTooltip : function(text){
38739 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38740 this.textEl.dom.qtip = text;
38741 this.textEl.dom.removeAttribute('title');
38743 this.textEl.dom.title = text;
38747 onTabClick : function(e){
38748 e.preventDefault();
38749 this.tabPanel.activate(this.id);
38752 onTabMouseDown : function(e){
38753 e.preventDefault();
38754 this.tabPanel.activate(this.id);
38757 getWidth : function(){
38758 return this.inner.getWidth();
38761 setWidth : function(width){
38762 var iwidth = width - this.linode.getPadding("lr");
38763 this.inner.setWidth(iwidth);
38764 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38765 this.linode.setWidth(width);
38769 * Show or hide the tab
38770 * @param {Boolean} hidden True to hide or false to show.
38772 setHidden : function(hidden){
38773 this.hidden = hidden;
38774 this.linode.setStyle("display", hidden ? "none" : "");
38778 * Returns true if this tab is "hidden"
38779 * @return {Boolean}
38781 isHidden : function(){
38782 return this.hidden;
38786 * Returns the text for this tab
38789 getText : function(){
38793 autoSize : function(){
38794 //this.el.beginMeasure();
38795 this.textEl.setWidth(1);
38797 * #2804 [new] Tabs in Roojs
38798 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38800 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38801 //this.el.endMeasure();
38805 * Sets the text for the tab (Note: this also sets the tooltip text)
38806 * @param {String} text The tab's text and tooltip
38808 setText : function(text){
38810 this.textEl.update(text);
38811 this.setTooltip(text);
38812 //if(!this.tabPanel.resizeTabs){
38813 // this.autoSize();
38817 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38819 activate : function(){
38820 this.tabPanel.activate(this.id);
38824 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38826 disable : function(){
38827 if(this.tabPanel.active != this){
38828 this.disabled = true;
38829 this.status_node.addClass("disabled");
38834 * Enables this TabPanelItem if it was previously disabled.
38836 enable : function(){
38837 this.disabled = false;
38838 this.status_node.removeClass("disabled");
38842 * Sets the content for this TabPanelItem.
38843 * @param {String} content The content
38844 * @param {Boolean} loadScripts true to look for and load scripts
38846 setContent : function(content, loadScripts){
38847 this.bodyEl.update(content, loadScripts);
38851 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38852 * @return {Roo.UpdateManager} The UpdateManager
38854 getUpdateManager : function(){
38855 return this.bodyEl.getUpdateManager();
38859 * Set a URL to be used to load the content for this TabPanelItem.
38860 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38861 * @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)
38862 * @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)
38863 * @return {Roo.UpdateManager} The UpdateManager
38865 setUrl : function(url, params, loadOnce){
38866 if(this.refreshDelegate){
38867 this.un('activate', this.refreshDelegate);
38869 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38870 this.on("activate", this.refreshDelegate);
38871 return this.bodyEl.getUpdateManager();
38875 _handleRefresh : function(url, params, loadOnce){
38876 if(!loadOnce || !this.loaded){
38877 var updater = this.bodyEl.getUpdateManager();
38878 updater.update(url, params, this._setLoaded.createDelegate(this));
38883 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38884 * Will fail silently if the setUrl method has not been called.
38885 * This does not activate the panel, just updates its content.
38887 refresh : function(){
38888 if(this.refreshDelegate){
38889 this.loaded = false;
38890 this.refreshDelegate();
38895 _setLoaded : function(){
38896 this.loaded = true;
38900 closeClick : function(e){
38903 this.fireEvent("beforeclose", this, o);
38904 if(o.cancel !== true){
38905 this.tabPanel.removeTab(this.id);
38909 * The text displayed in the tooltip for the close icon.
38912 closeText : "Close this tab"
38915 * This script refer to:
38916 * Title: International Telephone Input
38917 * Author: Jack O'Connor
38918 * Code version: v12.1.12
38919 * Availability: https://github.com/jackocnr/intl-tel-input.git
38922 Roo.bootstrap.PhoneInputData = function() {
38925 "Afghanistan (افغانستان)",
38930 "Albania (Shqipëri)",
38935 "Algeria (الجزائر)",
38960 "Antigua and Barbuda",
38970 "Armenia (Հայաստան)",
38986 "Austria (Österreich)",
38991 "Azerbaijan (Azərbaycan)",
39001 "Bahrain (البحرين)",
39006 "Bangladesh (বাংলাদেশ)",
39016 "Belarus (Беларусь)",
39021 "Belgium (België)",
39051 "Bosnia and Herzegovina (Босна и Херцеговина)",
39066 "British Indian Ocean Territory",
39071 "British Virgin Islands",
39081 "Bulgaria (България)",
39091 "Burundi (Uburundi)",
39096 "Cambodia (កម្ពុជា)",
39101 "Cameroon (Cameroun)",
39110 ["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"]
39113 "Cape Verde (Kabu Verdi)",
39118 "Caribbean Netherlands",
39129 "Central African Republic (République centrafricaine)",
39149 "Christmas Island",
39155 "Cocos (Keeling) Islands",
39166 "Comoros (جزر القمر)",
39171 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39176 "Congo (Republic) (Congo-Brazzaville)",
39196 "Croatia (Hrvatska)",
39217 "Czech Republic (Česká republika)",
39222 "Denmark (Danmark)",
39237 "Dominican Republic (República Dominicana)",
39241 ["809", "829", "849"]
39259 "Equatorial Guinea (Guinea Ecuatorial)",
39279 "Falkland Islands (Islas Malvinas)",
39284 "Faroe Islands (Føroyar)",
39305 "French Guiana (Guyane française)",
39310 "French Polynesia (Polynésie française)",
39325 "Georgia (საქართველო)",
39330 "Germany (Deutschland)",
39350 "Greenland (Kalaallit Nunaat)",
39387 "Guinea-Bissau (Guiné Bissau)",
39412 "Hungary (Magyarország)",
39417 "Iceland (Ísland)",
39437 "Iraq (العراق)",
39453 "Israel (ישראל)",
39480 "Jordan (الأردن)",
39485 "Kazakhstan (Казахстан)",
39506 "Kuwait (الكويت)",
39511 "Kyrgyzstan (Кыргызстан)",
39521 "Latvia (Latvija)",
39526 "Lebanon (لبنان)",
39541 "Libya (ليبيا)",
39551 "Lithuania (Lietuva)",
39566 "Macedonia (FYROM) (Македонија)",
39571 "Madagascar (Madagasikara)",
39601 "Marshall Islands",
39611 "Mauritania (موريتانيا)",
39616 "Mauritius (Moris)",
39637 "Moldova (Republica Moldova)",
39647 "Mongolia (Монгол)",
39652 "Montenegro (Crna Gora)",
39662 "Morocco (المغرب)",
39668 "Mozambique (Moçambique)",
39673 "Myanmar (Burma) (မြန်မာ)",
39678 "Namibia (Namibië)",
39693 "Netherlands (Nederland)",
39698 "New Caledonia (Nouvelle-Calédonie)",
39733 "North Korea (조선 민주주의 인민 공화국)",
39738 "Northern Mariana Islands",
39754 "Pakistan (پاکستان)",
39764 "Palestine (فلسطين)",
39774 "Papua New Guinea",
39816 "Réunion (La Réunion)",
39822 "Romania (România)",
39838 "Saint Barthélemy",
39849 "Saint Kitts and Nevis",
39859 "Saint Martin (Saint-Martin (partie française))",
39865 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39870 "Saint Vincent and the Grenadines",
39885 "São Tomé and Príncipe (São Tomé e Príncipe)",
39890 "Saudi Arabia (المملكة العربية السعودية)",
39895 "Senegal (Sénégal)",
39925 "Slovakia (Slovensko)",
39930 "Slovenia (Slovenija)",
39940 "Somalia (Soomaaliya)",
39950 "South Korea (대한민국)",
39955 "South Sudan (جنوب السودان)",
39965 "Sri Lanka (ශ්රී ලංකාව)",
39970 "Sudan (السودان)",
39980 "Svalbard and Jan Mayen",
39991 "Sweden (Sverige)",
39996 "Switzerland (Schweiz)",
40001 "Syria (سوريا)",
40046 "Trinidad and Tobago",
40051 "Tunisia (تونس)",
40056 "Turkey (Türkiye)",
40066 "Turks and Caicos Islands",
40076 "U.S. Virgin Islands",
40086 "Ukraine (Україна)",
40091 "United Arab Emirates (الإمارات العربية المتحدة)",
40113 "Uzbekistan (Oʻzbekiston)",
40123 "Vatican City (Città del Vaticano)",
40134 "Vietnam (Việt Nam)",
40139 "Wallis and Futuna (Wallis-et-Futuna)",
40144 "Western Sahara (الصحراء الغربية)",
40150 "Yemen (اليمن)",
40174 * This script refer to:
40175 * Title: International Telephone Input
40176 * Author: Jack O'Connor
40177 * Code version: v12.1.12
40178 * Availability: https://github.com/jackocnr/intl-tel-input.git
40182 * @class Roo.bootstrap.PhoneInput
40183 * @extends Roo.bootstrap.TriggerField
40184 * An input with International dial-code selection
40186 * @cfg {String} defaultDialCode default '+852'
40187 * @cfg {Array} preferedCountries default []
40190 * Create a new PhoneInput.
40191 * @param {Object} config Configuration options
40194 Roo.bootstrap.PhoneInput = function(config) {
40195 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40198 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40200 listWidth: undefined,
40202 selectedClass: 'active',
40204 invalidClass : "has-warning",
40206 validClass: 'has-success',
40208 allowed: '0123456789',
40213 * @cfg {String} defaultDialCode The default dial code when initializing the input
40215 defaultDialCode: '+852',
40218 * @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
40220 preferedCountries: false,
40222 getAutoCreate : function()
40224 var data = Roo.bootstrap.PhoneInputData();
40225 var align = this.labelAlign || this.parentLabelAlign();
40228 this.allCountries = [];
40229 this.dialCodeMapping = [];
40231 for (var i = 0; i < data.length; i++) {
40233 this.allCountries[i] = {
40237 priority: c[3] || 0,
40238 areaCodes: c[4] || null
40240 this.dialCodeMapping[c[2]] = {
40243 priority: c[3] || 0,
40244 areaCodes: c[4] || null
40256 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40257 maxlength: this.max_length,
40258 cls : 'form-control tel-input',
40259 autocomplete: 'new-password'
40262 var hiddenInput = {
40265 cls: 'hidden-tel-input'
40269 hiddenInput.name = this.name;
40272 if (this.disabled) {
40273 input.disabled = true;
40276 var flag_container = {
40293 cls: this.hasFeedback ? 'has-feedback' : '',
40299 cls: 'dial-code-holder',
40306 cls: 'roo-select2-container input-group',
40313 if (this.fieldLabel.length) {
40316 tooltip: 'This field is required'
40322 cls: 'control-label',
40328 html: this.fieldLabel
40331 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40337 if(this.indicatorpos == 'right') {
40338 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40345 if(align == 'left') {
40353 if(this.labelWidth > 12){
40354 label.style = "width: " + this.labelWidth + 'px';
40356 if(this.labelWidth < 13 && this.labelmd == 0){
40357 this.labelmd = this.labelWidth;
40359 if(this.labellg > 0){
40360 label.cls += ' col-lg-' + this.labellg;
40361 input.cls += ' col-lg-' + (12 - this.labellg);
40363 if(this.labelmd > 0){
40364 label.cls += ' col-md-' + this.labelmd;
40365 container.cls += ' col-md-' + (12 - this.labelmd);
40367 if(this.labelsm > 0){
40368 label.cls += ' col-sm-' + this.labelsm;
40369 container.cls += ' col-sm-' + (12 - this.labelsm);
40371 if(this.labelxs > 0){
40372 label.cls += ' col-xs-' + this.labelxs;
40373 container.cls += ' col-xs-' + (12 - this.labelxs);
40383 var settings = this;
40385 ['xs','sm','md','lg'].map(function(size){
40386 if (settings[size]) {
40387 cfg.cls += ' col-' + size + '-' + settings[size];
40391 this.store = new Roo.data.Store({
40392 proxy : new Roo.data.MemoryProxy({}),
40393 reader : new Roo.data.JsonReader({
40404 'name' : 'dialCode',
40408 'name' : 'priority',
40412 'name' : 'areaCodes',
40419 if(!this.preferedCountries) {
40420 this.preferedCountries = [
40427 var p = this.preferedCountries.reverse();
40430 for (var i = 0; i < p.length; i++) {
40431 for (var j = 0; j < this.allCountries.length; j++) {
40432 if(this.allCountries[j].iso2 == p[i]) {
40433 var t = this.allCountries[j];
40434 this.allCountries.splice(j,1);
40435 this.allCountries.unshift(t);
40441 this.store.proxy.data = {
40443 data: this.allCountries
40449 initEvents : function()
40452 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40454 this.indicator = this.indicatorEl();
40455 this.flag = this.flagEl();
40456 this.dialCodeHolder = this.dialCodeHolderEl();
40458 this.trigger = this.el.select('div.flag-box',true).first();
40459 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40464 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40465 _this.list.setWidth(lw);
40468 this.list.on('mouseover', this.onViewOver, this);
40469 this.list.on('mousemove', this.onViewMove, this);
40470 this.inputEl().on("keyup", this.onKeyUp, this);
40471 this.inputEl().on("keypress", this.onKeyPress, this);
40473 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40475 this.view = new Roo.View(this.list, this.tpl, {
40476 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40479 this.view.on('click', this.onViewClick, this);
40480 this.setValue(this.defaultDialCode);
40483 onTriggerClick : function(e)
40485 Roo.log('trigger click');
40490 if(this.isExpanded()){
40492 this.hasFocus = false;
40494 this.store.load({});
40495 this.hasFocus = true;
40500 isExpanded : function()
40502 return this.list.isVisible();
40505 collapse : function()
40507 if(!this.isExpanded()){
40511 Roo.get(document).un('mousedown', this.collapseIf, this);
40512 Roo.get(document).un('mousewheel', this.collapseIf, this);
40513 this.fireEvent('collapse', this);
40517 expand : function()
40521 if(this.isExpanded() || !this.hasFocus){
40525 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40526 this.list.setWidth(lw);
40529 this.restrictHeight();
40531 Roo.get(document).on('mousedown', this.collapseIf, this);
40532 Roo.get(document).on('mousewheel', this.collapseIf, this);
40534 this.fireEvent('expand', this);
40537 restrictHeight : function()
40539 this.list.alignTo(this.inputEl(), this.listAlign);
40540 this.list.alignTo(this.inputEl(), this.listAlign);
40543 onViewOver : function(e, t)
40545 if(this.inKeyMode){
40548 var item = this.view.findItemFromChild(t);
40551 var index = this.view.indexOf(item);
40552 this.select(index, false);
40557 onViewClick : function(view, doFocus, el, e)
40559 var index = this.view.getSelectedIndexes()[0];
40561 var r = this.store.getAt(index);
40564 this.onSelect(r, index);
40566 if(doFocus !== false && !this.blockFocus){
40567 this.inputEl().focus();
40571 onViewMove : function(e, t)
40573 this.inKeyMode = false;
40576 select : function(index, scrollIntoView)
40578 this.selectedIndex = index;
40579 this.view.select(index);
40580 if(scrollIntoView !== false){
40581 var el = this.view.getNode(index);
40583 this.list.scrollChildIntoView(el, false);
40588 createList : function()
40590 this.list = Roo.get(document.body).createChild({
40592 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40593 style: 'display:none'
40596 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40599 collapseIf : function(e)
40601 var in_combo = e.within(this.el);
40602 var in_list = e.within(this.list);
40603 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40605 if (in_combo || in_list || is_list) {
40611 onSelect : function(record, index)
40613 if(this.fireEvent('beforeselect', this, record, index) !== false){
40615 this.setFlagClass(record.data.iso2);
40616 this.setDialCode(record.data.dialCode);
40617 this.hasFocus = false;
40619 this.fireEvent('select', this, record, index);
40623 flagEl : function()
40625 var flag = this.el.select('div.flag',true).first();
40632 dialCodeHolderEl : function()
40634 var d = this.el.select('input.dial-code-holder',true).first();
40641 setDialCode : function(v)
40643 this.dialCodeHolder.dom.value = '+'+v;
40646 setFlagClass : function(n)
40648 this.flag.dom.className = 'flag '+n;
40651 getValue : function()
40653 var v = this.inputEl().getValue();
40654 if(this.dialCodeHolder) {
40655 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40660 setValue : function(v)
40662 var d = this.getDialCode(v);
40664 //invalid dial code
40665 if(v.length == 0 || !d || d.length == 0) {
40667 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40668 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40674 this.setFlagClass(this.dialCodeMapping[d].iso2);
40675 this.setDialCode(d);
40676 this.inputEl().dom.value = v.replace('+'+d,'');
40677 this.hiddenEl().dom.value = this.getValue();
40682 getDialCode : function(v)
40686 if (v.length == 0) {
40687 return this.dialCodeHolder.dom.value;
40691 if (v.charAt(0) != "+") {
40694 var numericChars = "";
40695 for (var i = 1; i < v.length; i++) {
40696 var c = v.charAt(i);
40699 if (this.dialCodeMapping[numericChars]) {
40700 dialCode = v.substr(1, i);
40702 if (numericChars.length == 4) {
40712 this.setValue(this.defaultDialCode);
40716 hiddenEl : function()
40718 return this.el.select('input.hidden-tel-input',true).first();
40721 // after setting val
40722 onKeyUp : function(e){
40723 this.setValue(this.getValue());
40726 onKeyPress : function(e){
40727 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40734 * @class Roo.bootstrap.MoneyField
40735 * @extends Roo.bootstrap.ComboBox
40736 * Bootstrap MoneyField class
40739 * Create a new MoneyField.
40740 * @param {Object} config Configuration options
40743 Roo.bootstrap.MoneyField = function(config) {
40745 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40749 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40752 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40754 allowDecimals : true,
40756 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40758 decimalSeparator : ".",
40760 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40762 decimalPrecision : 0,
40764 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40766 allowNegative : true,
40768 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40772 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40774 minValue : Number.NEGATIVE_INFINITY,
40776 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40778 maxValue : Number.MAX_VALUE,
40780 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40782 minText : "The minimum value for this field is {0}",
40784 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40786 maxText : "The maximum value for this field is {0}",
40788 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40789 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40791 nanText : "{0} is not a valid number",
40793 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40797 * @cfg {String} defaults currency of the MoneyField
40798 * value should be in lkey
40800 defaultCurrency : false,
40802 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40804 thousandsDelimiter : false,
40806 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40817 getAutoCreate : function()
40819 var align = this.labelAlign || this.parentLabelAlign();
40831 cls : 'form-control roo-money-amount-input',
40832 autocomplete: 'new-password'
40835 var hiddenInput = {
40839 cls: 'hidden-number-input'
40842 if(this.max_length) {
40843 input.maxlength = this.max_length;
40847 hiddenInput.name = this.name;
40850 if (this.disabled) {
40851 input.disabled = true;
40854 var clg = 12 - this.inputlg;
40855 var cmd = 12 - this.inputmd;
40856 var csm = 12 - this.inputsm;
40857 var cxs = 12 - this.inputxs;
40861 cls : 'row roo-money-field',
40865 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40869 cls: 'roo-select2-container input-group',
40873 cls : 'form-control roo-money-currency-input',
40874 autocomplete: 'new-password',
40876 name : this.currencyName
40880 cls : 'input-group-addon',
40894 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40898 cls: this.hasFeedback ? 'has-feedback' : '',
40909 if (this.fieldLabel.length) {
40912 tooltip: 'This field is required'
40918 cls: 'control-label',
40924 html: this.fieldLabel
40927 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40933 if(this.indicatorpos == 'right') {
40934 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40941 if(align == 'left') {
40949 if(this.labelWidth > 12){
40950 label.style = "width: " + this.labelWidth + 'px';
40952 if(this.labelWidth < 13 && this.labelmd == 0){
40953 this.labelmd = this.labelWidth;
40955 if(this.labellg > 0){
40956 label.cls += ' col-lg-' + this.labellg;
40957 input.cls += ' col-lg-' + (12 - this.labellg);
40959 if(this.labelmd > 0){
40960 label.cls += ' col-md-' + this.labelmd;
40961 container.cls += ' col-md-' + (12 - this.labelmd);
40963 if(this.labelsm > 0){
40964 label.cls += ' col-sm-' + this.labelsm;
40965 container.cls += ' col-sm-' + (12 - this.labelsm);
40967 if(this.labelxs > 0){
40968 label.cls += ' col-xs-' + this.labelxs;
40969 container.cls += ' col-xs-' + (12 - this.labelxs);
40980 var settings = this;
40982 ['xs','sm','md','lg'].map(function(size){
40983 if (settings[size]) {
40984 cfg.cls += ' col-' + size + '-' + settings[size];
40991 initEvents : function()
40993 this.indicator = this.indicatorEl();
40995 this.initCurrencyEvent();
40997 this.initNumberEvent();
41000 initCurrencyEvent : function()
41003 throw "can not find store for combo";
41006 this.store = Roo.factory(this.store, Roo.data);
41007 this.store.parent = this;
41011 this.triggerEl = this.el.select('.input-group-addon', true).first();
41013 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41018 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41019 _this.list.setWidth(lw);
41022 this.list.on('mouseover', this.onViewOver, this);
41023 this.list.on('mousemove', this.onViewMove, this);
41024 this.list.on('scroll', this.onViewScroll, this);
41027 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41030 this.view = new Roo.View(this.list, this.tpl, {
41031 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41034 this.view.on('click', this.onViewClick, this);
41036 this.store.on('beforeload', this.onBeforeLoad, this);
41037 this.store.on('load', this.onLoad, this);
41038 this.store.on('loadexception', this.onLoadException, this);
41040 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41041 "up" : function(e){
41042 this.inKeyMode = true;
41046 "down" : function(e){
41047 if(!this.isExpanded()){
41048 this.onTriggerClick();
41050 this.inKeyMode = true;
41055 "enter" : function(e){
41058 if(this.fireEvent("specialkey", this, e)){
41059 this.onViewClick(false);
41065 "esc" : function(e){
41069 "tab" : function(e){
41072 if(this.fireEvent("specialkey", this, e)){
41073 this.onViewClick(false);
41081 doRelay : function(foo, bar, hname){
41082 if(hname == 'down' || this.scope.isExpanded()){
41083 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41091 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41095 initNumberEvent : function(e)
41097 this.inputEl().on("keydown" , this.fireKey, this);
41098 this.inputEl().on("focus", this.onFocus, this);
41099 this.inputEl().on("blur", this.onBlur, this);
41101 this.inputEl().relayEvent('keyup', this);
41103 if(this.indicator){
41104 this.indicator.addClass('invisible');
41107 this.originalValue = this.getValue();
41109 if(this.validationEvent == 'keyup'){
41110 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41111 this.inputEl().on('keyup', this.filterValidation, this);
41113 else if(this.validationEvent !== false){
41114 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41117 if(this.selectOnFocus){
41118 this.on("focus", this.preFocus, this);
41121 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41122 this.inputEl().on("keypress", this.filterKeys, this);
41124 this.inputEl().relayEvent('keypress', this);
41127 var allowed = "0123456789";
41129 if(this.allowDecimals){
41130 allowed += this.decimalSeparator;
41133 if(this.allowNegative){
41137 if(this.thousandsDelimiter) {
41141 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41143 var keyPress = function(e){
41145 var k = e.getKey();
41147 var c = e.getCharCode();
41150 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41151 allowed.indexOf(String.fromCharCode(c)) === -1
41157 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41161 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41166 this.inputEl().on("keypress", keyPress, this);
41170 onTriggerClick : function(e)
41177 this.loadNext = false;
41179 if(this.isExpanded()){
41184 this.hasFocus = true;
41186 if(this.triggerAction == 'all') {
41187 this.doQuery(this.allQuery, true);
41191 this.doQuery(this.getRawValue());
41194 getCurrency : function()
41196 var v = this.currencyEl().getValue();
41201 restrictHeight : function()
41203 this.list.alignTo(this.currencyEl(), this.listAlign);
41204 this.list.alignTo(this.currencyEl(), this.listAlign);
41207 onViewClick : function(view, doFocus, el, e)
41209 var index = this.view.getSelectedIndexes()[0];
41211 var r = this.store.getAt(index);
41214 this.onSelect(r, index);
41218 onSelect : function(record, index){
41220 if(this.fireEvent('beforeselect', this, record, index) !== false){
41222 this.setFromCurrencyData(index > -1 ? record.data : false);
41226 this.fireEvent('select', this, record, index);
41230 setFromCurrencyData : function(o)
41234 this.lastCurrency = o;
41236 if (this.currencyField) {
41237 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41239 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41242 this.lastSelectionText = currency;
41244 //setting default currency
41245 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41246 this.setCurrency(this.defaultCurrency);
41250 this.setCurrency(currency);
41253 setFromData : function(o)
41257 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41259 this.setFromCurrencyData(c);
41264 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41266 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41269 this.setValue(value);
41273 setCurrency : function(v)
41275 this.currencyValue = v;
41278 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41283 setValue : function(v)
41285 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41291 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41293 this.inputEl().dom.value = (v == '') ? '' :
41294 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41296 if(!this.allowZero && v === '0') {
41297 this.hiddenEl().dom.value = '';
41298 this.inputEl().dom.value = '';
41305 getRawValue : function()
41307 var v = this.inputEl().getValue();
41312 getValue : function()
41314 return this.fixPrecision(this.parseValue(this.getRawValue()));
41317 parseValue : function(value)
41319 if(this.thousandsDelimiter) {
41321 r = new RegExp(",", "g");
41322 value = value.replace(r, "");
41325 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41326 return isNaN(value) ? '' : value;
41330 fixPrecision : function(value)
41332 if(this.thousandsDelimiter) {
41334 r = new RegExp(",", "g");
41335 value = value.replace(r, "");
41338 var nan = isNaN(value);
41340 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41341 return nan ? '' : value;
41343 return parseFloat(value).toFixed(this.decimalPrecision);
41346 decimalPrecisionFcn : function(v)
41348 return Math.floor(v);
41351 validateValue : function(value)
41353 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41357 var num = this.parseValue(value);
41360 this.markInvalid(String.format(this.nanText, value));
41364 if(num < this.minValue){
41365 this.markInvalid(String.format(this.minText, this.minValue));
41369 if(num > this.maxValue){
41370 this.markInvalid(String.format(this.maxText, this.maxValue));
41377 validate : function()
41379 if(this.disabled || this.allowBlank){
41384 var currency = this.getCurrency();
41386 if(this.validateValue(this.getRawValue()) && currency.length){
41391 this.markInvalid();
41395 getName: function()
41400 beforeBlur : function()
41406 var v = this.parseValue(this.getRawValue());
41413 onBlur : function()
41417 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41418 //this.el.removeClass(this.focusClass);
41421 this.hasFocus = false;
41423 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41427 var v = this.getValue();
41429 if(String(v) !== String(this.startValue)){
41430 this.fireEvent('change', this, v, this.startValue);
41433 this.fireEvent("blur", this);
41436 inputEl : function()
41438 return this.el.select('.roo-money-amount-input', true).first();
41441 currencyEl : function()
41443 return this.el.select('.roo-money-currency-input', true).first();
41446 hiddenEl : function()
41448 return this.el.select('input.hidden-number-input',true).first();