2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets, function(s) {
10 if (s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 addxtype : function(tree,cntr)
179 cn = Roo.factory(tree);
180 //Roo.log(['addxtype', cn]);
182 cn.parentType = this.xtype; //??
183 cn.parentId = this.id;
185 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 if (typeof(cn.container_method) == 'string') {
187 cntr = cn.container_method;
191 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
193 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
195 var build_from_html = Roo.XComponent.build_from_html;
197 var is_body = (tree.xtype == 'Body') ;
199 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
201 var self_cntr_el = Roo.get(this[cntr](false));
203 // do not try and build conditional elements
204 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
208 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
209 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
210 return this.addxtypeChild(tree,cntr, is_body);
213 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
216 return this.addxtypeChild(Roo.apply({}, tree),cntr);
219 Roo.log('skipping render');
225 if (!build_from_html) {
229 // this i think handles overlaying multiple children of the same type
230 // with the sam eelement.. - which might be buggy..
232 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
238 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
242 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
249 addxtypeChild : function (tree, cntr, is_body)
251 Roo.debug && Roo.log('addxtypeChild:' + cntr);
253 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
256 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
257 (typeof(tree['flexy:foreach']) != 'undefined');
261 skip_children = false;
262 // render the element if it's not BODY.
265 // if parent was disabled, then do not try and create the children..
266 if(!this[cntr](true)){
271 cn = Roo.factory(tree);
273 cn.parentType = this.xtype; //??
274 cn.parentId = this.id;
276 var build_from_html = Roo.XComponent.build_from_html;
279 // does the container contain child eleemnts with 'xtype' attributes.
280 // that match this xtype..
281 // note - when we render we create these as well..
282 // so we should check to see if body has xtype set.
283 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
285 var self_cntr_el = Roo.get(this[cntr](false));
286 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
288 //Roo.log(Roo.XComponent.build_from_html);
289 //Roo.log("got echild:");
292 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
293 // and are not displayed -this causes this to use up the wrong element when matching.
294 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
297 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
298 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
304 //echild.dom.removeAttribute('xtype');
306 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
307 Roo.debug && Roo.log(self_cntr_el);
308 Roo.debug && Roo.log(echild);
309 Roo.debug && Roo.log(cn);
315 // if object has flexy:if - then it may or may not be rendered.
316 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
317 // skip a flexy if element.
318 Roo.debug && Roo.log('skipping render');
319 Roo.debug && Roo.log(tree);
321 Roo.debug && Roo.log('skipping all children');
322 skip_children = true;
327 // actually if flexy:foreach is found, we really want to create
328 // multiple copies here...
330 //Roo.log(this[cntr]());
331 // some elements do not have render methods.. like the layouts...
333 if(this[cntr](true) === false){
338 cn.render && cn.render(this[cntr](true));
341 // then add the element..
348 if (typeof (tree.menu) != 'undefined') {
349 tree.menu.parentType = cn.xtype;
350 tree.menu.triggerEl = cn.el;
351 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
355 if (!tree.items || !tree.items.length) {
357 //Roo.log(["no children", this]);
362 var items = tree.items;
365 //Roo.log(items.length);
367 if (!skip_children) {
368 for(var i =0;i < items.length;i++) {
369 // Roo.log(['add child', items[i]]);
370 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
376 //Roo.log("fire childrenrendered");
378 cn.fireEvent('childrenrendered', this);
384 * Set the element that will be used to show or hide
386 setVisibilityEl : function(el)
388 this.visibilityEl = el;
392 * Get the element that will be used to show or hide
394 getVisibilityEl : function()
396 if (typeof(this.visibilityEl) == 'object') {
397 return this.visibilityEl;
400 if (typeof(this.visibilityEl) == 'string') {
401 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
408 * Show a component - removes 'hidden' class
412 if(!this.getVisibilityEl()){
416 this.getVisibilityEl().removeClass(['hidden','d-none']);
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass(['hidden','d-none']);
433 this.fireEvent('hide', this);
446 * @class Roo.bootstrap.Body
447 * @extends Roo.bootstrap.Component
448 * Bootstrap Body class
452 * @param {Object} config The config object
455 Roo.bootstrap.Body = function(config){
457 config = config || {};
459 Roo.bootstrap.Body.superclass.constructor.call(this, config);
460 this.el = Roo.get(config.el ? config.el : document.body );
461 if (this.cls && this.cls.length) {
462 Roo.get(document.body).addClass(this.cls);
466 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
468 is_body : true,// just to make sure it's constructed?
473 onRender : function(ct, position)
475 /* Roo.log("Roo.bootstrap.Body - onRender");
476 if (this.cls && this.cls.length) {
477 Roo.get(document.body).addClass(this.cls);
496 * @class Roo.bootstrap.ButtonGroup
497 * @extends Roo.bootstrap.Component
498 * Bootstrap ButtonGroup class
499 * @cfg {String} size lg | sm | xs (default empty normal)
500 * @cfg {String} align vertical | justified (default none)
501 * @cfg {String} direction up | down (default down)
502 * @cfg {Boolean} toolbar false | true
503 * @cfg {Boolean} btn true | false
508 * @param {Object} config The config object
511 Roo.bootstrap.ButtonGroup = function(config){
512 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
515 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
523 getAutoCreate : function(){
529 cfg.html = this.html || cfg.html;
540 if (['vertical','justified'].indexOf(this.align)!==-1) {
541 cfg.cls = 'btn-group-' + this.align;
543 if (this.align == 'justified') {
544 console.log(this.items);
548 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
549 cfg.cls += ' btn-group-' + this.size;
552 if (this.direction == 'up') {
553 cfg.cls += ' dropup' ;
559 * Add a button to the group (similar to NavItem API.)
561 addItem : function(cfg)
563 var cn = new Roo.bootstrap.Button(cfg);
565 cn.parentId = this.id;
566 cn.onRender(this.el, null);
580 * @class Roo.bootstrap.Button
581 * @extends Roo.bootstrap.Component
582 * Bootstrap Button class
583 * @cfg {String} html The button content
584 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
585 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
586 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
587 * @cfg {String} size ( lg | sm | xs)
588 * @cfg {String} tag ( a | input | submit)
589 * @cfg {String} href empty or href
590 * @cfg {Boolean} disabled default false;
591 * @cfg {Boolean} isClose default false;
592 * @cfg {String} glyphicon depricated - use fa
593 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
594 * @cfg {String} badge text for badge
595 * @cfg {String} theme (default|glow)
596 * @cfg {Boolean} inverse dark themed version
597 * @cfg {Boolean} toggle is it a slidy toggle button
598 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
599 * @cfg {String} ontext text for on slidy toggle state
600 * @cfg {String} offtext text for off slidy toggle state
601 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
602 * @cfg {Boolean} removeClass remove the standard class..
603 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
606 * Create a new button
607 * @param {Object} config The config object
611 Roo.bootstrap.Button = function(config){
612 Roo.bootstrap.Button.superclass.constructor.call(this, config);
613 this.weightClass = ["btn-default btn-outline-secondary",
625 * When a butotn is pressed
626 * @param {Roo.bootstrap.Button} btn
627 * @param {Roo.EventObject} e
632 * After the button has been toggles
633 * @param {Roo.bootstrap.Button} btn
634 * @param {Roo.EventObject} e
635 * @param {boolean} pressed (also available as button.pressed)
641 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
662 preventDefault: true,
670 getAutoCreate : function(){
678 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
679 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
684 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
686 if (this.toggle == true) {
689 cls: 'slider-frame roo-button',
694 'data-off-text':'OFF',
695 cls: 'slider-button',
701 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
702 cfg.cls += ' '+this.weight;
711 cfg["aria-hidden"] = true;
713 cfg.html = "×";
719 if (this.theme==='default') {
720 cfg.cls = 'btn roo-button';
722 //if (this.parentType != 'Navbar') {
723 this.weight = this.weight.length ? this.weight : 'default';
725 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
727 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
728 var weight = this.weight == 'default' ? 'secondary' : this.weight;
729 cfg.cls += ' btn-' + outline + weight;
730 if (this.weight == 'default') {
732 cfg.cls += ' btn-' + this.weight;
735 } else if (this.theme==='glow') {
738 cfg.cls = 'btn-glow roo-button';
740 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
742 cfg.cls += ' ' + this.weight;
748 this.cls += ' inverse';
752 if (this.active || this.pressed === true) {
753 cfg.cls += ' active';
757 cfg.disabled = 'disabled';
761 Roo.log('changing to ul' );
763 this.glyphicon = 'caret';
764 if (Roo.bootstrap.version == 4) {
765 this.fa = 'caret-down';
770 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
772 //gsRoo.log(this.parentType);
773 if (this.parentType === 'Navbar' && !this.parent().bar) {
774 Roo.log('changing to li?');
783 href : this.href || '#'
786 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
787 cfg.cls += ' dropdown';
794 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
796 if (this.glyphicon) {
797 cfg.html = ' ' + cfg.html;
802 cls: 'glyphicon glyphicon-' + this.glyphicon
807 cfg.html = ' ' + cfg.html;
812 cls: 'fa fas fa-' + this.fa
822 // cfg.cls='btn roo-button';
826 var value = cfg.html;
831 cls: 'glyphicon glyphicon-' + this.glyphicon,
838 cls: 'fa fas fa-' + this.fa,
843 var bw = this.badge_weight.length ? this.badge_weight :
844 (this.weight.length ? this.weight : 'secondary');
845 bw = bw == 'default' ? 'secondary' : bw;
851 cls: 'badge badge-' + bw,
860 cfg.cls += ' dropdown';
861 cfg.html = typeof(cfg.html) != 'undefined' ?
862 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
865 if (cfg.tag !== 'a' && this.href !== '') {
866 throw "Tag must be a to set href.";
867 } else if (this.href.length > 0) {
868 cfg.href = this.href;
871 if(this.removeClass){
876 cfg.target = this.target;
881 initEvents: function() {
882 // Roo.log('init events?');
883 // Roo.log(this.el.dom);
886 if (typeof (this.menu) != 'undefined') {
887 this.menu.parentType = this.xtype;
888 this.menu.triggerEl = this.el;
889 this.addxtype(Roo.apply({}, this.menu));
893 if (this.el.hasClass('roo-button')) {
894 this.el.on('click', this.onClick, this);
896 this.el.select('.roo-button').on('click', this.onClick, this);
899 if(this.removeClass){
900 this.el.on('click', this.onClick, this);
903 this.el.enableDisplayMode();
906 onClick : function(e)
912 Roo.log('button on click ');
913 if(this.preventDefault){
917 if (this.pressed === true || this.pressed === false) {
918 this.toggleActive(e);
922 this.fireEvent('click', this, e);
926 * Enables this button
930 this.disabled = false;
931 this.el.removeClass('disabled');
935 * Disable this button
939 this.disabled = true;
940 this.el.addClass('disabled');
943 * sets the active state on/off,
944 * @param {Boolean} state (optional) Force a particular state
946 setActive : function(v) {
948 this.el[v ? 'addClass' : 'removeClass']('active');
952 * toggles the current active state
954 toggleActive : function(e)
956 this.setActive(!this.pressed);
957 this.fireEvent('toggle', this, e, !this.pressed);
960 * get the current active state
961 * @return {boolean} true if it's active
963 isActive : function()
965 return this.el.hasClass('active');
968 * set the text of the first selected button
970 setText : function(str)
972 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
975 * get the text of the first selected button
979 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
982 setWeight : function(str)
984 this.el.removeClass(this.weightClass);
986 var outline = this.outline ? 'outline-' : '';
987 if (str == 'default') {
988 this.el.addClass('btn-default btn-outline-secondary');
991 this.el.addClass('btn-' + outline + str);
1005 * @class Roo.bootstrap.Column
1006 * @extends Roo.bootstrap.Component
1007 * Bootstrap Column class
1008 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1009 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1010 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1011 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1012 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1013 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1014 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1015 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1018 * @cfg {Boolean} hidden (true|false) hide the element
1019 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1020 * @cfg {String} fa (ban|check|...) font awesome icon
1021 * @cfg {Number} fasize (1|2|....) font awsome size
1023 * @cfg {String} icon (info-sign|check|...) glyphicon name
1025 * @cfg {String} html content of column.
1028 * Create a new Column
1029 * @param {Object} config The config object
1032 Roo.bootstrap.Column = function(config){
1033 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1036 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1054 getAutoCreate : function(){
1055 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1063 ['xs','sm','md','lg'].map(function(size){
1064 //Roo.log( size + ':' + settings[size]);
1066 if (settings[size+'off'] !== false) {
1067 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1070 if (settings[size] === false) {
1074 if (!settings[size]) { // 0 = hidden
1075 cfg.cls += ' hidden-' + size;
1078 cfg.cls += ' col-' + size + '-' + settings[size];
1083 cfg.cls += ' hidden';
1086 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1087 cfg.cls +=' alert alert-' + this.alert;
1091 if (this.html.length) {
1092 cfg.html = this.html;
1096 if (this.fasize > 1) {
1097 fasize = ' fa-' + this.fasize + 'x';
1099 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1104 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1123 * @class Roo.bootstrap.Container
1124 * @extends Roo.bootstrap.Component
1125 * Bootstrap Container class
1126 * @cfg {Boolean} jumbotron is it a jumbotron element
1127 * @cfg {String} html content of element
1128 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1129 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1130 * @cfg {String} header content of header (for panel)
1131 * @cfg {String} footer content of footer (for panel)
1132 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1133 * @cfg {String} tag (header|aside|section) type of HTML tag.
1134 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1135 * @cfg {String} fa font awesome icon
1136 * @cfg {String} icon (info-sign|check|...) glyphicon name
1137 * @cfg {Boolean} hidden (true|false) hide the element
1138 * @cfg {Boolean} expandable (true|false) default false
1139 * @cfg {Boolean} expanded (true|false) default true
1140 * @cfg {String} rheader contet on the right of header
1141 * @cfg {Boolean} clickable (true|false) default false
1145 * Create a new Container
1146 * @param {Object} config The config object
1149 Roo.bootstrap.Container = function(config){
1150 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1156 * After the panel has been expand
1158 * @param {Roo.bootstrap.Container} this
1163 * After the panel has been collapsed
1165 * @param {Roo.bootstrap.Container} this
1170 * When a element is chick
1171 * @param {Roo.bootstrap.Container} this
1172 * @param {Roo.EventObject} e
1178 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1196 getChildContainer : function() {
1202 if (this.panel.length) {
1203 return this.el.select('.panel-body',true).first();
1210 getAutoCreate : function(){
1213 tag : this.tag || 'div',
1217 if (this.jumbotron) {
1218 cfg.cls = 'jumbotron';
1223 // - this is applied by the parent..
1225 // cfg.cls = this.cls + '';
1228 if (this.sticky.length) {
1230 var bd = Roo.get(document.body);
1231 if (!bd.hasClass('bootstrap-sticky')) {
1232 bd.addClass('bootstrap-sticky');
1233 Roo.select('html',true).setStyle('height', '100%');
1236 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1240 if (this.well.length) {
1241 switch (this.well) {
1244 cfg.cls +=' well well-' +this.well;
1253 cfg.cls += ' hidden';
1257 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1258 cfg.cls +=' alert alert-' + this.alert;
1263 if (this.panel.length) {
1264 cfg.cls += ' panel panel-' + this.panel;
1266 if (this.header.length) {
1270 if(this.expandable){
1272 cfg.cls = cfg.cls + ' expandable';
1276 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1284 cls : 'panel-title',
1285 html : (this.expandable ? ' ' : '') + this.header
1289 cls: 'panel-header-right',
1295 cls : 'panel-heading',
1296 style : this.expandable ? 'cursor: pointer' : '',
1304 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1309 if (this.footer.length) {
1311 cls : 'panel-footer',
1320 body.html = this.html || cfg.html;
1321 // prefix with the icons..
1323 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1326 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1331 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1332 cfg.cls = 'container';
1338 initEvents: function()
1340 if(this.expandable){
1341 var headerEl = this.headerEl();
1344 headerEl.on('click', this.onToggleClick, this);
1349 this.el.on('click', this.onClick, this);
1354 onToggleClick : function()
1356 var headerEl = this.headerEl();
1372 if(this.fireEvent('expand', this)) {
1374 this.expanded = true;
1376 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1378 this.el.select('.panel-body',true).first().removeClass('hide');
1380 var toggleEl = this.toggleEl();
1386 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1391 collapse : function()
1393 if(this.fireEvent('collapse', this)) {
1395 this.expanded = false;
1397 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1398 this.el.select('.panel-body',true).first().addClass('hide');
1400 var toggleEl = this.toggleEl();
1406 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1410 toggleEl : function()
1412 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1416 return this.el.select('.panel-heading .fa',true).first();
1419 headerEl : function()
1421 if(!this.el || !this.panel.length || !this.header.length){
1425 return this.el.select('.panel-heading',true).first()
1430 if(!this.el || !this.panel.length){
1434 return this.el.select('.panel-body',true).first()
1437 titleEl : function()
1439 if(!this.el || !this.panel.length || !this.header.length){
1443 return this.el.select('.panel-title',true).first();
1446 setTitle : function(v)
1448 var titleEl = this.titleEl();
1454 titleEl.dom.innerHTML = v;
1457 getTitle : function()
1460 var titleEl = this.titleEl();
1466 return titleEl.dom.innerHTML;
1469 setRightTitle : function(v)
1471 var t = this.el.select('.panel-header-right',true).first();
1477 t.dom.innerHTML = v;
1480 onClick : function(e)
1484 this.fireEvent('click', this, e);
1497 * @class Roo.bootstrap.Img
1498 * @extends Roo.bootstrap.Component
1499 * Bootstrap Img class
1500 * @cfg {Boolean} imgResponsive false | true
1501 * @cfg {String} border rounded | circle | thumbnail
1502 * @cfg {String} src image source
1503 * @cfg {String} alt image alternative text
1504 * @cfg {String} href a tag href
1505 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1506 * @cfg {String} xsUrl xs image source
1507 * @cfg {String} smUrl sm image source
1508 * @cfg {String} mdUrl md image source
1509 * @cfg {String} lgUrl lg image source
1512 * Create a new Input
1513 * @param {Object} config The config object
1516 Roo.bootstrap.Img = function(config){
1517 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1523 * The img click event for the img.
1524 * @param {Roo.EventObject} e
1530 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1532 imgResponsive: true,
1542 getAutoCreate : function()
1544 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1545 return this.createSingleImg();
1550 cls: 'roo-image-responsive-group',
1555 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1557 if(!_this[size + 'Url']){
1563 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1564 html: _this.html || cfg.html,
1565 src: _this[size + 'Url']
1568 img.cls += ' roo-image-responsive-' + size;
1570 var s = ['xs', 'sm', 'md', 'lg'];
1572 s.splice(s.indexOf(size), 1);
1574 Roo.each(s, function(ss){
1575 img.cls += ' hidden-' + ss;
1578 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1579 cfg.cls += ' img-' + _this.border;
1583 cfg.alt = _this.alt;
1596 a.target = _this.target;
1600 cfg.cn.push((_this.href) ? a : img);
1607 createSingleImg : function()
1611 cls: (this.imgResponsive) ? 'img-responsive' : '',
1613 src : 'about:blank' // just incase src get's set to undefined?!?
1616 cfg.html = this.html || cfg.html;
1618 cfg.src = this.src || cfg.src;
1620 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1621 cfg.cls += ' img-' + this.border;
1638 a.target = this.target;
1643 return (this.href) ? a : cfg;
1646 initEvents: function()
1649 this.el.on('click', this.onClick, this);
1654 onClick : function(e)
1656 Roo.log('img onclick');
1657 this.fireEvent('click', this, e);
1660 * Sets the url of the image - used to update it
1661 * @param {String} url the url of the image
1664 setSrc : function(url)
1668 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1669 this.el.dom.src = url;
1673 this.el.select('img', true).first().dom.src = url;
1689 * @class Roo.bootstrap.Link
1690 * @extends Roo.bootstrap.Component
1691 * Bootstrap Link Class
1692 * @cfg {String} alt image alternative text
1693 * @cfg {String} href a tag href
1694 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1695 * @cfg {String} html the content of the link.
1696 * @cfg {String} anchor name for the anchor link
1697 * @cfg {String} fa - favicon
1699 * @cfg {Boolean} preventDefault (true | false) default false
1703 * Create a new Input
1704 * @param {Object} config The config object
1707 Roo.bootstrap.Link = function(config){
1708 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1714 * The img click event for the img.
1715 * @param {Roo.EventObject} e
1721 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1725 preventDefault: false,
1731 getAutoCreate : function()
1733 var html = this.html || '';
1735 if (this.fa !== false) {
1736 html = '<i class="fa fa-' + this.fa + '"></i>';
1741 // anchor's do not require html/href...
1742 if (this.anchor === false) {
1744 cfg.href = this.href || '#';
1746 cfg.name = this.anchor;
1747 if (this.html !== false || this.fa !== false) {
1750 if (this.href !== false) {
1751 cfg.href = this.href;
1755 if(this.alt !== false){
1760 if(this.target !== false) {
1761 cfg.target = this.target;
1767 initEvents: function() {
1769 if(!this.href || this.preventDefault){
1770 this.el.on('click', this.onClick, this);
1774 onClick : function(e)
1776 if(this.preventDefault){
1779 //Roo.log('img onclick');
1780 this.fireEvent('click', this, e);
1793 * @class Roo.bootstrap.Header
1794 * @extends Roo.bootstrap.Component
1795 * Bootstrap Header class
1796 * @cfg {String} html content of header
1797 * @cfg {Number} level (1|2|3|4|5|6) default 1
1800 * Create a new Header
1801 * @param {Object} config The config object
1805 Roo.bootstrap.Header = function(config){
1806 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1809 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1817 getAutoCreate : function(){
1822 tag: 'h' + (1 *this.level),
1823 html: this.html || ''
1835 * Ext JS Library 1.1.1
1836 * Copyright(c) 2006-2007, Ext JS, LLC.
1838 * Originally Released Under LGPL - original licence link has changed is not relivant.
1841 * <script type="text/javascript">
1845 * @class Roo.bootstrap.MenuMgr
1846 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1849 Roo.bootstrap.MenuMgr = function(){
1850 var menus, active, groups = {}, attached = false, lastShow = new Date();
1852 // private - called when first menu is created
1855 active = new Roo.util.MixedCollection();
1856 Roo.get(document).addKeyListener(27, function(){
1857 if(active.length > 0){
1865 if(active && active.length > 0){
1866 var c = active.clone();
1876 if(active.length < 1){
1877 Roo.get(document).un("mouseup", onMouseDown);
1885 var last = active.last();
1886 lastShow = new Date();
1889 Roo.get(document).on("mouseup", onMouseDown);
1894 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1895 m.parentMenu.activeChild = m;
1896 }else if(last && last.isVisible()){
1897 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1902 function onBeforeHide(m){
1904 m.activeChild.hide();
1906 if(m.autoHideTimer){
1907 clearTimeout(m.autoHideTimer);
1908 delete m.autoHideTimer;
1913 function onBeforeShow(m){
1914 var pm = m.parentMenu;
1915 if(!pm && !m.allowOtherMenus){
1917 }else if(pm && pm.activeChild && active != m){
1918 pm.activeChild.hide();
1922 // private this should really trigger on mouseup..
1923 function onMouseDown(e){
1924 Roo.log("on Mouse Up");
1926 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1927 Roo.log("MenuManager hideAll");
1936 function onBeforeCheck(mi, state){
1938 var g = groups[mi.group];
1939 for(var i = 0, l = g.length; i < l; i++){
1941 g[i].setChecked(false);
1950 * Hides all menus that are currently visible
1952 hideAll : function(){
1957 register : function(menu){
1961 menus[menu.id] = menu;
1962 menu.on("beforehide", onBeforeHide);
1963 menu.on("hide", onHide);
1964 menu.on("beforeshow", onBeforeShow);
1965 menu.on("show", onShow);
1967 if(g && menu.events["checkchange"]){
1971 groups[g].push(menu);
1972 menu.on("checkchange", onCheck);
1977 * Returns a {@link Roo.menu.Menu} object
1978 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1979 * be used to generate and return a new Menu instance.
1981 get : function(menu){
1982 if(typeof menu == "string"){ // menu id
1984 }else if(menu.events){ // menu instance
1987 /*else if(typeof menu.length == 'number'){ // array of menu items?
1988 return new Roo.bootstrap.Menu({items:menu});
1989 }else{ // otherwise, must be a config
1990 return new Roo.bootstrap.Menu(menu);
1997 unregister : function(menu){
1998 delete menus[menu.id];
1999 menu.un("beforehide", onBeforeHide);
2000 menu.un("hide", onHide);
2001 menu.un("beforeshow", onBeforeShow);
2002 menu.un("show", onShow);
2004 if(g && menu.events["checkchange"]){
2005 groups[g].remove(menu);
2006 menu.un("checkchange", onCheck);
2011 registerCheckable : function(menuItem){
2012 var g = menuItem.group;
2017 groups[g].push(menuItem);
2018 menuItem.on("beforecheckchange", onBeforeCheck);
2023 unregisterCheckable : function(menuItem){
2024 var g = menuItem.group;
2026 groups[g].remove(menuItem);
2027 menuItem.un("beforecheckchange", onBeforeCheck);
2039 * @class Roo.bootstrap.Menu
2040 * @extends Roo.bootstrap.Component
2041 * Bootstrap Menu class - container for MenuItems
2042 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2043 * @cfg {bool} hidden if the menu should be hidden when rendered.
2044 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2045 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2049 * @param {Object} config The config object
2053 Roo.bootstrap.Menu = function(config){
2054 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2055 if (this.registerMenu && this.type != 'treeview') {
2056 Roo.bootstrap.MenuMgr.register(this);
2063 * Fires before this menu is displayed (return false to block)
2064 * @param {Roo.menu.Menu} this
2069 * Fires before this menu is hidden (return false to block)
2070 * @param {Roo.menu.Menu} this
2075 * Fires after this menu is displayed
2076 * @param {Roo.menu.Menu} this
2081 * Fires after this menu is hidden
2082 * @param {Roo.menu.Menu} this
2087 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2088 * @param {Roo.menu.Menu} this
2089 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2090 * @param {Roo.EventObject} e
2095 * Fires when the mouse is hovering over this menu
2096 * @param {Roo.menu.Menu} this
2097 * @param {Roo.EventObject} e
2098 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2103 * Fires when the mouse exits this menu
2104 * @param {Roo.menu.Menu} this
2105 * @param {Roo.EventObject} e
2106 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2111 * Fires when a menu item contained in this menu is clicked
2112 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2113 * @param {Roo.EventObject} e
2117 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2120 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2124 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2127 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2129 registerMenu : true,
2131 menuItems :false, // stores the menu items..
2141 getChildContainer : function() {
2145 getAutoCreate : function(){
2147 //if (['right'].indexOf(this.align)!==-1) {
2148 // cfg.cn[1].cls += ' pull-right'
2154 cls : 'dropdown-menu' ,
2155 style : 'z-index:1000'
2159 if (this.type === 'submenu') {
2160 cfg.cls = 'submenu active';
2162 if (this.type === 'treeview') {
2163 cfg.cls = 'treeview-menu';
2168 initEvents : function() {
2170 // Roo.log("ADD event");
2171 // Roo.log(this.triggerEl.dom);
2173 this.triggerEl.on('click', this.onTriggerClick, this);
2175 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2178 if (this.triggerEl.hasClass('nav-item')) {
2179 // dropdown toggle on the 'a' in BS4?
2180 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2182 this.triggerEl.addClass('dropdown-toggle');
2185 this.el.on('touchstart' , this.onTouch, this);
2187 this.el.on('click' , this.onClick, this);
2189 this.el.on("mouseover", this.onMouseOver, this);
2190 this.el.on("mouseout", this.onMouseOut, this);
2194 findTargetItem : function(e)
2196 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2200 //Roo.log(t); Roo.log(t.id);
2202 //Roo.log(this.menuitems);
2203 return this.menuitems.get(t.id);
2205 //return this.items.get(t.menuItemId);
2211 onTouch : function(e)
2213 Roo.log("menu.onTouch");
2214 //e.stopEvent(); this make the user popdown broken
2218 onClick : function(e)
2220 Roo.log("menu.onClick");
2222 var t = this.findTargetItem(e);
2223 if(!t || t.isContainer){
2228 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2229 if(t == this.activeItem && t.shouldDeactivate(e)){
2230 this.activeItem.deactivate();
2231 delete this.activeItem;
2235 this.setActiveItem(t, true);
2243 Roo.log('pass click event');
2247 this.fireEvent("click", this, t, e);
2251 if(!t.href.length || t.href == '#'){
2252 (function() { _this.hide(); }).defer(100);
2257 onMouseOver : function(e){
2258 var t = this.findTargetItem(e);
2261 // if(t.canActivate && !t.disabled){
2262 // this.setActiveItem(t, true);
2266 this.fireEvent("mouseover", this, e, t);
2268 isVisible : function(){
2269 return !this.hidden;
2271 onMouseOut : function(e){
2272 var t = this.findTargetItem(e);
2275 // if(t == this.activeItem && t.shouldDeactivate(e)){
2276 // this.activeItem.deactivate();
2277 // delete this.activeItem;
2280 this.fireEvent("mouseout", this, e, t);
2285 * Displays this menu relative to another element
2286 * @param {String/HTMLElement/Roo.Element} element The element to align to
2287 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2288 * the element (defaults to this.defaultAlign)
2289 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2291 show : function(el, pos, parentMenu)
2293 if (false === this.fireEvent("beforeshow", this)) {
2294 Roo.log("show canceled");
2297 this.parentMenu = parentMenu;
2302 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2305 * Displays this menu at a specific xy position
2306 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2307 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2309 showAt : function(xy, parentMenu, /* private: */_e){
2310 this.parentMenu = parentMenu;
2315 this.fireEvent("beforeshow", this);
2316 //xy = this.el.adjustForConstraints(xy);
2320 this.hideMenuItems();
2321 this.hidden = false;
2322 this.triggerEl.addClass('open');
2323 this.el.addClass('show');
2325 // reassign x when hitting right
2326 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2327 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2330 // reassign y when hitting bottom
2331 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2332 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2335 // but the list may align on trigger left or trigger top... should it be a properity?
2337 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2342 this.fireEvent("show", this);
2348 this.doFocus.defer(50, this);
2352 doFocus : function(){
2354 this.focusEl.focus();
2359 * Hides this menu and optionally all parent menus
2360 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2362 hide : function(deep)
2364 if (false === this.fireEvent("beforehide", this)) {
2365 Roo.log("hide canceled");
2368 this.hideMenuItems();
2369 if(this.el && this.isVisible()){
2371 if(this.activeItem){
2372 this.activeItem.deactivate();
2373 this.activeItem = null;
2375 this.triggerEl.removeClass('open');;
2376 this.el.removeClass('show');
2378 this.fireEvent("hide", this);
2380 if(deep === true && this.parentMenu){
2381 this.parentMenu.hide(true);
2385 onTriggerClick : function(e)
2387 Roo.log('trigger click');
2389 var target = e.getTarget();
2391 Roo.log(target.nodeName.toLowerCase());
2393 if(target.nodeName.toLowerCase() === 'i'){
2399 onTriggerPress : function(e)
2401 Roo.log('trigger press');
2402 //Roo.log(e.getTarget());
2403 // Roo.log(this.triggerEl.dom);
2405 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2406 var pel = Roo.get(e.getTarget());
2407 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2408 Roo.log('is treeview or dropdown?');
2412 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2416 if (this.isVisible()) {
2421 this.show(this.triggerEl, '?', false);
2424 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2431 hideMenuItems : function()
2433 Roo.log("hide Menu Items");
2438 this.el.select('.open',true).each(function(aa) {
2440 aa.removeClass('open');
2444 addxtypeChild : function (tree, cntr) {
2445 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2447 this.menuitems.add(comp);
2459 this.getEl().dom.innerHTML = '';
2460 this.menuitems.clear();
2474 * @class Roo.bootstrap.MenuItem
2475 * @extends Roo.bootstrap.Component
2476 * Bootstrap MenuItem class
2477 * @cfg {String} html the menu label
2478 * @cfg {String} href the link
2479 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2480 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2481 * @cfg {Boolean} active used on sidebars to highlight active itesm
2482 * @cfg {String} fa favicon to show on left of menu item.
2483 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2487 * Create a new MenuItem
2488 * @param {Object} config The config object
2492 Roo.bootstrap.MenuItem = function(config){
2493 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2498 * The raw click event for the entire grid.
2499 * @param {Roo.bootstrap.MenuItem} this
2500 * @param {Roo.EventObject} e
2506 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2510 preventDefault: false,
2511 isContainer : false,
2515 getAutoCreate : function(){
2517 if(this.isContainer){
2520 cls: 'dropdown-menu-item '
2530 cls : 'dropdown-item',
2535 if (this.fa !== false) {
2538 cls : 'fa fa-' + this.fa
2547 cls: 'dropdown-menu-item',
2550 if (this.parent().type == 'treeview') {
2551 cfg.cls = 'treeview-menu';
2554 cfg.cls += ' active';
2559 anc.href = this.href || cfg.cn[0].href ;
2560 ctag.html = this.html || cfg.cn[0].html ;
2564 initEvents: function()
2566 if (this.parent().type == 'treeview') {
2567 this.el.select('a').on('click', this.onClick, this);
2571 this.menu.parentType = this.xtype;
2572 this.menu.triggerEl = this.el;
2573 this.menu = this.addxtype(Roo.apply({}, this.menu));
2577 onClick : function(e)
2579 Roo.log('item on click ');
2581 if(this.preventDefault){
2584 //this.parent().hideMenuItems();
2586 this.fireEvent('click', this, e);
2605 * @class Roo.bootstrap.MenuSeparator
2606 * @extends Roo.bootstrap.Component
2607 * Bootstrap MenuSeparator class
2610 * Create a new MenuItem
2611 * @param {Object} config The config object
2615 Roo.bootstrap.MenuSeparator = function(config){
2616 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2619 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2621 getAutoCreate : function(){
2640 * @class Roo.bootstrap.Modal
2641 * @extends Roo.bootstrap.Component
2642 * Bootstrap Modal class
2643 * @cfg {String} title Title of dialog
2644 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2645 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2646 * @cfg {Boolean} specificTitle default false
2647 * @cfg {Array} buttons Array of buttons or standard button set..
2648 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2649 * @cfg {Boolean} animate default true
2650 * @cfg {Boolean} allow_close default true
2651 * @cfg {Boolean} fitwindow default false
2652 * @cfg {String} size (sm|lg) default empty
2653 * @cfg {Number} max_width set the max width of modal
2657 * Create a new Modal Dialog
2658 * @param {Object} config The config object
2661 Roo.bootstrap.Modal = function(config){
2662 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2667 * The raw btnclick event for the button
2668 * @param {Roo.EventObject} e
2673 * Fire when dialog resize
2674 * @param {Roo.bootstrap.Modal} this
2675 * @param {Roo.EventObject} e
2679 this.buttons = this.buttons || [];
2682 this.tmpl = Roo.factory(this.tmpl);
2687 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2689 title : 'test dialog',
2699 specificTitle: false,
2701 buttonPosition: 'right',
2724 onRender : function(ct, position)
2726 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2729 var cfg = Roo.apply({}, this.getAutoCreate());
2732 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2734 //if (!cfg.name.length) {
2738 cfg.cls += ' ' + this.cls;
2741 cfg.style = this.style;
2743 this.el = Roo.get(document.body).createChild(cfg, position);
2745 //var type = this.el.dom.type;
2748 if(this.tabIndex !== undefined){
2749 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2752 this.dialogEl = this.el.select('.modal-dialog',true).first();
2753 this.bodyEl = this.el.select('.modal-body',true).first();
2754 this.closeEl = this.el.select('.modal-header .close', true).first();
2755 this.headerEl = this.el.select('.modal-header',true).first();
2756 this.titleEl = this.el.select('.modal-title',true).first();
2757 this.footerEl = this.el.select('.modal-footer',true).first();
2759 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2761 //this.el.addClass("x-dlg-modal");
2763 if (this.buttons.length) {
2764 Roo.each(this.buttons, function(bb) {
2765 var b = Roo.apply({}, bb);
2766 b.xns = b.xns || Roo.bootstrap;
2767 b.xtype = b.xtype || 'Button';
2768 if (typeof(b.listeners) == 'undefined') {
2769 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2772 var btn = Roo.factory(b);
2774 btn.render(this.getButtonContainer());
2778 // render the children.
2781 if(typeof(this.items) != 'undefined'){
2782 var items = this.items;
2785 for(var i =0;i < items.length;i++) {
2786 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2790 this.items = nitems;
2792 // where are these used - they used to be body/close/footer
2796 //this.el.addClass([this.fieldClass, this.cls]);
2800 getAutoCreate : function()
2804 html : this.html || ''
2809 cls : 'modal-title',
2813 if(this.specificTitle){
2819 if (this.allow_close && Roo.bootstrap.version == 3) {
2829 if (this.allow_close && Roo.bootstrap.version == 4) {
2839 if(this.size.length){
2840 size = 'modal-' + this.size;
2843 var footer = Roo.bootstrap.version == 3 ?
2845 cls : 'modal-footer',
2849 cls: 'btn-' + this.buttonPosition
2854 { // BS4 uses mr-auto on left buttons....
2855 cls : 'modal-footer'
2866 cls: "modal-dialog " + size,
2869 cls : "modal-content",
2872 cls : 'modal-header',
2887 modal.cls += ' fade';
2893 getChildContainer : function() {
2898 getButtonContainer : function() {
2900 return Roo.bootstrap.version == 4 ?
2901 this.el.select('.modal-footer',true).first()
2902 : this.el.select('.modal-footer div',true).first();
2905 initEvents : function()
2907 if (this.allow_close) {
2908 this.closeEl.on('click', this.hide, this);
2910 Roo.EventManager.onWindowResize(this.resize, this, true);
2918 this.maskEl.setSize(
2919 Roo.lib.Dom.getViewWidth(true),
2920 Roo.lib.Dom.getViewHeight(true)
2923 if (this.fitwindow) {
2927 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2928 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
2933 if(this.max_width !== 0) {
2935 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2938 this.setSize(w, this.height);
2942 if(this.max_height) {
2943 this.setSize(w,Math.min(
2945 Roo.lib.Dom.getViewportHeight(true) - 60
2951 if(!this.fit_content) {
2952 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2956 this.setSize(w, Math.min(
2958 this.headerEl.getHeight() +
2959 this.footerEl.getHeight() +
2960 this.getChildHeight(this.bodyEl.dom.childNodes),
2961 Roo.lib.Dom.getViewportHeight(true) - 60)
2967 setSize : function(w,h)
2978 if (!this.rendered) {
2982 //this.el.setStyle('display', 'block');
2983 this.el.removeClass('hideing');
2984 this.el.dom.style.display='block';
2986 Roo.get(document.body).addClass('modal-open');
2988 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2991 this.el.addClass('show');
2992 this.el.addClass('in');
2995 this.el.addClass('show');
2996 this.el.addClass('in');
2999 // not sure how we can show data in here..
3001 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3004 Roo.get(document.body).addClass("x-body-masked");
3006 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3007 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3008 this.maskEl.dom.style.display = 'block';
3009 this.maskEl.addClass('show');
3014 this.fireEvent('show', this);
3016 // set zindex here - otherwise it appears to be ignored...
3017 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3020 this.items.forEach( function(e) {
3021 e.layout ? e.layout() : false;
3029 if(this.fireEvent("beforehide", this) !== false){
3031 this.maskEl.removeClass('show');
3033 this.maskEl.dom.style.display = '';
3034 Roo.get(document.body).removeClass("x-body-masked");
3035 this.el.removeClass('in');
3036 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3038 if(this.animate){ // why
3039 this.el.addClass('hideing');
3040 this.el.removeClass('show');
3042 if (!this.el.hasClass('hideing')) {
3043 return; // it's been shown again...
3046 this.el.dom.style.display='';
3048 Roo.get(document.body).removeClass('modal-open');
3049 this.el.removeClass('hideing');
3053 this.el.removeClass('show');
3054 this.el.dom.style.display='';
3055 Roo.get(document.body).removeClass('modal-open');
3058 this.fireEvent('hide', this);
3061 isVisible : function()
3064 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3068 addButton : function(str, cb)
3072 var b = Roo.apply({}, { html : str } );
3073 b.xns = b.xns || Roo.bootstrap;
3074 b.xtype = b.xtype || 'Button';
3075 if (typeof(b.listeners) == 'undefined') {
3076 b.listeners = { click : cb.createDelegate(this) };
3079 var btn = Roo.factory(b);
3081 btn.render(this.getButtonContainer());
3087 setDefaultButton : function(btn)
3089 //this.el.select('.modal-footer').()
3092 resizeTo: function(w,h)
3094 this.dialogEl.setWidth(w);
3096 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
3098 this.bodyEl.setHeight(h - diff);
3100 this.fireEvent('resize', this);
3103 setContentSize : function(w, h)
3107 onButtonClick: function(btn,e)
3110 this.fireEvent('btnclick', btn.name, e);
3113 * Set the title of the Dialog
3114 * @param {String} str new Title
3116 setTitle: function(str) {
3117 this.titleEl.dom.innerHTML = str;
3120 * Set the body of the Dialog
3121 * @param {String} str new Title
3123 setBody: function(str) {
3124 this.bodyEl.dom.innerHTML = str;
3127 * Set the body of the Dialog using the template
3128 * @param {Obj} data - apply this data to the template and replace the body contents.
3130 applyBody: function(obj)
3133 Roo.log("Error - using apply Body without a template");
3136 this.tmpl.overwrite(this.bodyEl, obj);
3139 getChildHeight : function(child_nodes)
3143 child_nodes.length == 0
3148 var child_height = 0;
3150 for(var i = 0; i < child_nodes.length; i++) {
3153 * for modal with tabs...
3154 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3156 var layout_childs = child_nodes[i].childNodes;
3158 for(var j = 0; j < layout_childs.length; j++) {
3160 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3162 var layout_body_childs = layout_childs[j].childNodes;
3164 for(var k = 0; k < layout_body_childs.length; k++) {
3166 if(layout_body_childs[k].classList.contains('navbar')) {
3167 child_height += layout_body_childs[k].offsetHeight;
3171 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3173 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3175 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3177 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3178 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3193 child_height += child_nodes[i].offsetHeight;
3194 // Roo.log(child_nodes[i].offsetHeight);
3197 return child_height;
3203 Roo.apply(Roo.bootstrap.Modal, {
3205 * Button config that displays a single OK button
3214 * Button config that displays Yes and No buttons
3230 * Button config that displays OK and Cancel buttons
3245 * Button config that displays Yes, No and Cancel buttons
3269 * messagebox - can be used as a replace
3273 * @class Roo.MessageBox
3274 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3278 Roo.Msg.alert('Status', 'Changes saved successfully.');
3280 // Prompt for user data:
3281 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3283 // process text value...
3287 // Show a dialog using config options:
3289 title:'Save Changes?',
3290 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3291 buttons: Roo.Msg.YESNOCANCEL,
3298 Roo.bootstrap.MessageBox = function(){
3299 var dlg, opt, mask, waitTimer;
3300 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3301 var buttons, activeTextEl, bwidth;
3305 var handleButton = function(button){
3307 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3311 var handleHide = function(){
3313 dlg.el.removeClass(opt.cls);
3316 // Roo.TaskMgr.stop(waitTimer);
3317 // waitTimer = null;
3322 var updateButtons = function(b){
3325 buttons["ok"].hide();
3326 buttons["cancel"].hide();
3327 buttons["yes"].hide();
3328 buttons["no"].hide();
3329 dlg.footerEl.hide();
3333 dlg.footerEl.show();
3334 for(var k in buttons){
3335 if(typeof buttons[k] != "function"){
3338 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3339 width += buttons[k].el.getWidth()+15;
3349 var handleEsc = function(d, k, e){
3350 if(opt && opt.closable !== false){
3360 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3361 * @return {Roo.BasicDialog} The BasicDialog element
3363 getDialog : function(){
3365 dlg = new Roo.bootstrap.Modal( {
3368 //constraintoviewport:false,
3370 //collapsible : false,
3375 //buttonAlign:"center",
3376 closeClick : function(){
3377 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3380 handleButton("cancel");
3385 dlg.on("hide", handleHide);
3387 //dlg.addKeyListener(27, handleEsc);
3389 this.buttons = buttons;
3390 var bt = this.buttonText;
3391 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3392 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3393 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3394 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3396 bodyEl = dlg.bodyEl.createChild({
3398 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3399 '<textarea class="roo-mb-textarea"></textarea>' +
3400 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3402 msgEl = bodyEl.dom.firstChild;
3403 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3404 textboxEl.enableDisplayMode();
3405 textboxEl.addKeyListener([10,13], function(){
3406 if(dlg.isVisible() && opt && opt.buttons){
3409 }else if(opt.buttons.yes){
3410 handleButton("yes");
3414 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3415 textareaEl.enableDisplayMode();
3416 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3417 progressEl.enableDisplayMode();
3419 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3420 var pf = progressEl.dom.firstChild;
3422 pp = Roo.get(pf.firstChild);
3423 pp.setHeight(pf.offsetHeight);
3431 * Updates the message box body text
3432 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3433 * the XHTML-compliant non-breaking space character '&#160;')
3434 * @return {Roo.MessageBox} This message box
3436 updateText : function(text)
3438 if(!dlg.isVisible() && !opt.width){
3439 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3440 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3442 msgEl.innerHTML = text || ' ';
3444 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3445 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3447 Math.min(opt.width || cw , this.maxWidth),
3448 Math.max(opt.minWidth || this.minWidth, bwidth)
3451 activeTextEl.setWidth(w);
3453 if(dlg.isVisible()){
3454 dlg.fixedcenter = false;
3456 // to big, make it scroll. = But as usual stupid IE does not support
3459 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3460 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3461 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3463 bodyEl.dom.style.height = '';
3464 bodyEl.dom.style.overflowY = '';
3467 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3469 bodyEl.dom.style.overflowX = '';
3472 dlg.setContentSize(w, bodyEl.getHeight());
3473 if(dlg.isVisible()){
3474 dlg.fixedcenter = true;
3480 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3481 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3482 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3483 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3484 * @return {Roo.MessageBox} This message box
3486 updateProgress : function(value, text){
3488 this.updateText(text);
3491 if (pp) { // weird bug on my firefox - for some reason this is not defined
3492 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3493 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3499 * Returns true if the message box is currently displayed
3500 * @return {Boolean} True if the message box is visible, else false
3502 isVisible : function(){
3503 return dlg && dlg.isVisible();
3507 * Hides the message box if it is displayed
3510 if(this.isVisible()){
3516 * Displays a new message box, or reinitializes an existing message box, based on the config options
3517 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3518 * The following config object properties are supported:
3520 Property Type Description
3521 ---------- --------------- ------------------------------------------------------------------------------------
3522 animEl String/Element An id or Element from which the message box should animate as it opens and
3523 closes (defaults to undefined)
3524 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3525 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3526 closable Boolean False to hide the top-right close button (defaults to true). Note that
3527 progress and wait dialogs will ignore this property and always hide the
3528 close button as they can only be closed programmatically.
3529 cls String A custom CSS class to apply to the message box element
3530 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3531 displayed (defaults to 75)
3532 fn Function A callback function to execute after closing the dialog. The arguments to the
3533 function will be btn (the name of the button that was clicked, if applicable,
3534 e.g. "ok"), and text (the value of the active text field, if applicable).
3535 Progress and wait dialogs will ignore this option since they do not respond to
3536 user actions and can only be closed programmatically, so any required function
3537 should be called by the same code after it closes the dialog.
3538 icon String A CSS class that provides a background image to be used as an icon for
3539 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3540 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3541 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3542 modal Boolean False to allow user interaction with the page while the message box is
3543 displayed (defaults to true)
3544 msg String A string that will replace the existing message box body text (defaults
3545 to the XHTML-compliant non-breaking space character ' ')
3546 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3547 progress Boolean True to display a progress bar (defaults to false)
3548 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3549 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3550 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3551 title String The title text
3552 value String The string value to set into the active textbox element if displayed
3553 wait Boolean True to display a progress bar (defaults to false)
3554 width Number The width of the dialog in pixels
3561 msg: 'Please enter your address:',
3563 buttons: Roo.MessageBox.OKCANCEL,
3566 animEl: 'addAddressBtn'
3569 * @param {Object} config Configuration options
3570 * @return {Roo.MessageBox} This message box
3572 show : function(options)
3575 // this causes nightmares if you show one dialog after another
3576 // especially on callbacks..
3578 if(this.isVisible()){
3581 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3582 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3583 Roo.log("New Dialog Message:" + options.msg )
3584 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3585 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3588 var d = this.getDialog();
3590 d.setTitle(opt.title || " ");
3591 d.closeEl.setDisplayed(opt.closable !== false);
3592 activeTextEl = textboxEl;
3593 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3598 textareaEl.setHeight(typeof opt.multiline == "number" ?
3599 opt.multiline : this.defaultTextHeight);
3600 activeTextEl = textareaEl;
3609 progressEl.setDisplayed(opt.progress === true);
3611 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3613 this.updateProgress(0);
3614 activeTextEl.dom.value = opt.value || "";
3616 dlg.setDefaultButton(activeTextEl);
3618 var bs = opt.buttons;
3622 }else if(bs && bs.yes){
3623 db = buttons["yes"];
3625 dlg.setDefaultButton(db);
3627 bwidth = updateButtons(opt.buttons);
3628 this.updateText(opt.msg);
3630 d.el.addClass(opt.cls);
3632 d.proxyDrag = opt.proxyDrag === true;
3633 d.modal = opt.modal !== false;
3634 d.mask = opt.modal !== false ? mask : false;
3636 // force it to the end of the z-index stack so it gets a cursor in FF
3637 document.body.appendChild(dlg.el.dom);
3638 d.animateTarget = null;
3639 d.show(options.animEl);
3645 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3646 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3647 * and closing the message box when the process is complete.
3648 * @param {String} title The title bar text
3649 * @param {String} msg The message box body text
3650 * @return {Roo.MessageBox} This message box
3652 progress : function(title, msg){
3659 minWidth: this.minProgressWidth,
3666 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3667 * If a callback function is passed it will be called after the user clicks the button, and the
3668 * id of the button that was clicked will be passed as the only parameter to the callback
3669 * (could also be the top-right close button).
3670 * @param {String} title The title bar text
3671 * @param {String} msg The message box body text
3672 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3673 * @param {Object} scope (optional) The scope of the callback function
3674 * @return {Roo.MessageBox} This message box
3676 alert : function(title, msg, fn, scope)
3691 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3692 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3693 * You are responsible for closing the message box when the process is complete.
3694 * @param {String} msg The message box body text
3695 * @param {String} title (optional) The title bar text
3696 * @return {Roo.MessageBox} This message box
3698 wait : function(msg, title){
3709 waitTimer = Roo.TaskMgr.start({
3711 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3719 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3720 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3721 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3722 * @param {String} title The title bar text
3723 * @param {String} msg The message box body text
3724 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3725 * @param {Object} scope (optional) The scope of the callback function
3726 * @return {Roo.MessageBox} This message box
3728 confirm : function(title, msg, fn, scope){
3732 buttons: this.YESNO,
3741 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3742 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3743 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3744 * (could also be the top-right close button) and the text that was entered will be passed as the two
3745 * parameters to the callback.
3746 * @param {String} title The title bar text
3747 * @param {String} msg The message box body text
3748 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3749 * @param {Object} scope (optional) The scope of the callback function
3750 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3751 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3752 * @return {Roo.MessageBox} This message box
3754 prompt : function(title, msg, fn, scope, multiline){
3758 buttons: this.OKCANCEL,
3763 multiline: multiline,
3770 * Button config that displays a single OK button
3775 * Button config that displays Yes and No buttons
3778 YESNO : {yes:true, no:true},
3780 * Button config that displays OK and Cancel buttons
3783 OKCANCEL : {ok:true, cancel:true},
3785 * Button config that displays Yes, No and Cancel buttons
3788 YESNOCANCEL : {yes:true, no:true, cancel:true},
3791 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3794 defaultTextHeight : 75,
3796 * The maximum width in pixels of the message box (defaults to 600)
3801 * The minimum width in pixels of the message box (defaults to 100)
3806 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3807 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3810 minProgressWidth : 250,
3812 * An object containing the default button text strings that can be overriden for localized language support.
3813 * Supported properties are: ok, cancel, yes and no.
3814 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3827 * Shorthand for {@link Roo.MessageBox}
3829 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3830 Roo.Msg = Roo.Msg || Roo.MessageBox;
3839 * @class Roo.bootstrap.Navbar
3840 * @extends Roo.bootstrap.Component
3841 * Bootstrap Navbar class
3844 * Create a new Navbar
3845 * @param {Object} config The config object
3849 Roo.bootstrap.Navbar = function(config){
3850 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3854 * @event beforetoggle
3855 * Fire before toggle the menu
3856 * @param {Roo.EventObject} e
3858 "beforetoggle" : true
3862 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3871 getAutoCreate : function(){
3874 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3878 initEvents :function ()
3880 //Roo.log(this.el.select('.navbar-toggle',true));
3881 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
3888 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3890 var size = this.el.getSize();
3891 this.maskEl.setSize(size.width, size.height);
3892 this.maskEl.enableDisplayMode("block");
3901 getChildContainer : function()
3903 if (this.el && this.el.select('.collapse').getCount()) {
3904 return this.el.select('.collapse',true).first();
3919 onToggle : function()
3922 if(this.fireEvent('beforetoggle', this) === false){
3925 var ce = this.el.select('.navbar-collapse',true).first();
3927 if (!ce.hasClass('show')) {
3937 * Expand the navbar pulldown
3939 expand : function ()
3942 var ce = this.el.select('.navbar-collapse',true).first();
3943 if (ce.hasClass('collapsing')) {
3946 ce.dom.style.height = '';
3948 ce.addClass('in'); // old...
3949 ce.removeClass('collapse');
3950 ce.addClass('show');
3951 var h = ce.getHeight();
3953 ce.removeClass('show');
3954 // at this point we should be able to see it..
3955 ce.addClass('collapsing');
3957 ce.setHeight(0); // resize it ...
3958 ce.on('transitionend', function() {
3959 //Roo.log('done transition');
3960 ce.removeClass('collapsing');
3961 ce.addClass('show');
3962 ce.removeClass('collapse');
3964 ce.dom.style.height = '';
3965 }, this, { single: true} );
3967 ce.dom.scrollTop = 0;
3970 * Collapse the navbar pulldown
3972 collapse : function()
3974 var ce = this.el.select('.navbar-collapse',true).first();
3976 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
3977 // it's collapsed or collapsing..
3980 ce.removeClass('in'); // old...
3981 ce.setHeight(ce.getHeight());
3982 ce.removeClass('show');
3983 ce.addClass('collapsing');
3985 ce.on('transitionend', function() {
3986 ce.dom.style.height = '';
3987 ce.removeClass('collapsing');
3988 ce.addClass('collapse');
3989 }, this, { single: true} );
4009 * @class Roo.bootstrap.NavSimplebar
4010 * @extends Roo.bootstrap.Navbar
4011 * Bootstrap Sidebar class
4013 * @cfg {Boolean} inverse is inverted color
4015 * @cfg {String} type (nav | pills | tabs)
4016 * @cfg {Boolean} arrangement stacked | justified
4017 * @cfg {String} align (left | right) alignment
4019 * @cfg {Boolean} main (true|false) main nav bar? default false
4020 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
4022 * @cfg {String} tag (header|footer|nav|div) default is nav
4024 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
4028 * Create a new Sidebar
4029 * @param {Object} config The config object
4033 Roo.bootstrap.NavSimplebar = function(config){
4034 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4037 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4053 getAutoCreate : function(){
4057 tag : this.tag || 'div',
4058 cls : 'navbar navbar-expand-lg roo-navbar-simple'
4060 if (['light','white'].indexOf(this.weight) > -1) {
4061 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4063 cfg.cls += ' bg-' + this.weight;
4066 cfg.cls += ' navbar-inverse';
4070 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4072 //if (Roo.bootstrap.version == 4) {
4084 this.type = this.type || 'nav';
4085 if (['tabs','pills'].indexOf(this.type) != -1) {
4086 cfg.cn[0].cls += ' nav-' + this.type
4090 if (this.type!=='nav') {
4091 Roo.log('nav type must be nav/tabs/pills')
4093 cfg.cn[0].cls += ' navbar-nav'
4099 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4100 cfg.cn[0].cls += ' nav-' + this.arrangement;
4104 if (this.align === 'right') {
4105 cfg.cn[0].cls += ' navbar-right';
4130 * navbar-expand-md fixed-top
4134 * @class Roo.bootstrap.NavHeaderbar
4135 * @extends Roo.bootstrap.NavSimplebar
4136 * Bootstrap Sidebar class
4138 * @cfg {String} brand what is brand
4139 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4140 * @cfg {String} brand_href href of the brand
4141 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4142 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4143 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4144 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4147 * Create a new Sidebar
4148 * @param {Object} config The config object
4152 Roo.bootstrap.NavHeaderbar = function(config){
4153 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4157 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4164 desktopCenter : false,
4167 getAutoCreate : function(){
4170 tag: this.nav || 'nav',
4171 cls: 'navbar navbar-expand-md',
4177 if (this.desktopCenter) {
4178 cn.push({cls : 'container', cn : []});
4186 cls: 'navbar-toggle navbar-toggler',
4187 'data-toggle': 'collapse',
4192 html: 'Toggle navigation'
4196 cls: 'icon-bar navbar-toggler-icon'
4209 cn.push( Roo.bootstrap.version == 4 ? btn : {
4211 cls: 'navbar-header',
4220 cls: 'collapse navbar-collapse',
4224 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4226 if (['light','white'].indexOf(this.weight) > -1) {
4227 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4229 cfg.cls += ' bg-' + this.weight;
4232 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4233 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4235 // tag can override this..
4237 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4240 if (this.brand !== '') {
4241 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4242 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4244 href: this.brand_href ? this.brand_href : '#',
4245 cls: 'navbar-brand',
4253 cfg.cls += ' main-nav';
4261 getHeaderChildContainer : function()
4263 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4264 return this.el.select('.navbar-header',true).first();
4267 return this.getChildContainer();
4271 initEvents : function()
4273 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4275 if (this.autohide) {
4280 Roo.get(document).on('scroll',function(e) {
4281 var ns = Roo.get(document).getScroll().top;
4282 var os = prevScroll;
4286 ft.removeClass('slideDown');
4287 ft.addClass('slideUp');
4290 ft.removeClass('slideUp');
4291 ft.addClass('slideDown');
4312 * @class Roo.bootstrap.NavSidebar
4313 * @extends Roo.bootstrap.Navbar
4314 * Bootstrap Sidebar class
4317 * Create a new Sidebar
4318 * @param {Object} config The config object
4322 Roo.bootstrap.NavSidebar = function(config){
4323 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4326 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4328 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4330 getAutoCreate : function(){
4335 cls: 'sidebar sidebar-nav'
4357 * @class Roo.bootstrap.NavGroup
4358 * @extends Roo.bootstrap.Component
4359 * Bootstrap NavGroup class
4360 * @cfg {String} align (left|right)
4361 * @cfg {Boolean} inverse
4362 * @cfg {String} type (nav|pills|tab) default nav
4363 * @cfg {String} navId - reference Id for navbar.
4367 * Create a new nav group
4368 * @param {Object} config The config object
4371 Roo.bootstrap.NavGroup = function(config){
4372 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4375 Roo.bootstrap.NavGroup.register(this);
4379 * Fires when the active item changes
4380 * @param {Roo.bootstrap.NavGroup} this
4381 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4382 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4389 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4400 getAutoCreate : function()
4402 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4408 if (Roo.bootstrap.version == 4) {
4409 if (['tabs','pills'].indexOf(this.type) != -1) {
4410 cfg.cls += ' nav-' + this.type;
4412 cfg.cls += ' navbar-nav';
4415 if (['tabs','pills'].indexOf(this.type) != -1) {
4416 cfg.cls += ' nav-' + this.type
4418 if (this.type !== 'nav') {
4419 Roo.log('nav type must be nav/tabs/pills')
4421 cfg.cls += ' navbar-nav'
4425 if (this.parent() && this.parent().sidebar) {
4428 cls: 'dashboard-menu sidebar-menu'
4434 if (this.form === true) {
4437 cls: 'navbar-form form-inline'
4440 if (this.align === 'right') {
4441 cfg.cls += ' navbar-right ml-md-auto';
4443 cfg.cls += ' navbar-left';
4447 if (this.align === 'right') {
4448 cfg.cls += ' navbar-right ml-md-auto';
4450 cfg.cls += ' mr-auto';
4454 cfg.cls += ' navbar-inverse';
4462 * sets the active Navigation item
4463 * @param {Roo.bootstrap.NavItem} the new current navitem
4465 setActiveItem : function(item)
4468 Roo.each(this.navItems, function(v){
4473 v.setActive(false, true);
4480 item.setActive(true, true);
4481 this.fireEvent('changed', this, item, prev);
4486 * gets the active Navigation item
4487 * @return {Roo.bootstrap.NavItem} the current navitem
4489 getActive : function()
4493 Roo.each(this.navItems, function(v){
4504 indexOfNav : function()
4508 Roo.each(this.navItems, function(v,i){
4519 * adds a Navigation item
4520 * @param {Roo.bootstrap.NavItem} the navitem to add
4522 addItem : function(cfg)
4524 if (this.form && Roo.bootstrap.version == 4) {
4527 var cn = new Roo.bootstrap.NavItem(cfg);
4529 cn.parentId = this.id;
4530 cn.onRender(this.el, null);
4534 * register a Navigation item
4535 * @param {Roo.bootstrap.NavItem} the navitem to add
4537 register : function(item)
4539 this.navItems.push( item);
4540 item.navId = this.navId;
4545 * clear all the Navigation item
4548 clearAll : function()
4551 this.el.dom.innerHTML = '';
4554 getNavItem: function(tabId)
4557 Roo.each(this.navItems, function(e) {
4558 if (e.tabId == tabId) {
4568 setActiveNext : function()
4570 var i = this.indexOfNav(this.getActive());
4571 if (i > this.navItems.length) {
4574 this.setActiveItem(this.navItems[i+1]);
4576 setActivePrev : function()
4578 var i = this.indexOfNav(this.getActive());
4582 this.setActiveItem(this.navItems[i-1]);
4584 clearWasActive : function(except) {
4585 Roo.each(this.navItems, function(e) {
4586 if (e.tabId != except.tabId && e.was_active) {
4587 e.was_active = false;
4594 getWasActive : function ()
4597 Roo.each(this.navItems, function(e) {
4612 Roo.apply(Roo.bootstrap.NavGroup, {
4616 * register a Navigation Group
4617 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4619 register : function(navgrp)
4621 this.groups[navgrp.navId] = navgrp;
4625 * fetch a Navigation Group based on the navigation ID
4626 * @param {string} the navgroup to add
4627 * @returns {Roo.bootstrap.NavGroup} the navgroup
4629 get: function(navId) {
4630 if (typeof(this.groups[navId]) == 'undefined') {
4632 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4634 return this.groups[navId] ;
4649 * @class Roo.bootstrap.NavItem
4650 * @extends Roo.bootstrap.Component
4651 * Bootstrap Navbar.NavItem class
4652 * @cfg {String} href link to
4653 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4655 * @cfg {String} html content of button
4656 * @cfg {String} badge text inside badge
4657 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4658 * @cfg {String} glyphicon DEPRICATED - use fa
4659 * @cfg {String} icon DEPRICATED - use fa
4660 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4661 * @cfg {Boolean} active Is item active
4662 * @cfg {Boolean} disabled Is item disabled
4664 * @cfg {Boolean} preventDefault (true | false) default false
4665 * @cfg {String} tabId the tab that this item activates.
4666 * @cfg {String} tagtype (a|span) render as a href or span?
4667 * @cfg {Boolean} animateRef (true|false) link to element default false
4670 * Create a new Navbar Item
4671 * @param {Object} config The config object
4673 Roo.bootstrap.NavItem = function(config){
4674 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4679 * The raw click event for the entire grid.
4680 * @param {Roo.EventObject} e
4685 * Fires when the active item active state changes
4686 * @param {Roo.bootstrap.NavItem} this
4687 * @param {boolean} state the new state
4693 * Fires when scroll to element
4694 * @param {Roo.bootstrap.NavItem} this
4695 * @param {Object} options
4696 * @param {Roo.EventObject} e
4704 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4713 preventDefault : false,
4721 button_outline : false,
4725 getAutoCreate : function(){
4733 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4735 if (this.disabled) {
4736 cfg.cls += ' disabled';
4740 if (this.button_weight.length) {
4741 cfg.tag = this.href ? 'a' : 'button';
4742 cfg.html = this.html || '';
4743 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4745 cfg.href = this.href;
4748 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4751 // menu .. should add dropdown-menu class - so no need for carat..
4753 if (this.badge !== '') {
4755 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4760 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4764 href : this.href || "#",
4765 html: this.html || ''
4768 if (this.tagtype == 'a') {
4769 cfg.cn[0].cls = 'nav-link';
4772 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4775 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4777 if(this.glyphicon) {
4778 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4783 cfg.cn[0].html += " <span class='caret'></span>";
4787 if (this.badge !== '') {
4789 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4797 onRender : function(ct, position)
4799 // Roo.log("Call onRender: " + this.xtype);
4800 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4804 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4805 this.navLink = this.el.select('.nav-link',true).first();
4810 initEvents: function()
4812 if (typeof (this.menu) != 'undefined') {
4813 this.menu.parentType = this.xtype;
4814 this.menu.triggerEl = this.el;
4815 this.menu = this.addxtype(Roo.apply({}, this.menu));
4818 this.el.select('a',true).on('click', this.onClick, this);
4820 if(this.tagtype == 'span'){
4821 this.el.select('span',true).on('click', this.onClick, this);
4824 // at this point parent should be available..
4825 this.parent().register(this);
4828 onClick : function(e)
4830 if (e.getTarget('.dropdown-menu-item')) {
4831 // did you click on a menu itemm.... - then don't trigger onclick..
4836 this.preventDefault ||
4839 Roo.log("NavItem - prevent Default?");
4843 if (this.disabled) {
4847 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4848 if (tg && tg.transition) {
4849 Roo.log("waiting for the transitionend");
4855 //Roo.log("fire event clicked");
4856 if(this.fireEvent('click', this, e) === false){
4860 if(this.tagtype == 'span'){
4864 //Roo.log(this.href);
4865 var ael = this.el.select('a',true).first();
4868 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4869 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4870 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4871 return; // ignore... - it's a 'hash' to another page.
4873 Roo.log("NavItem - prevent Default?");
4875 this.scrollToElement(e);
4879 var p = this.parent();
4881 if (['tabs','pills'].indexOf(p.type)!==-1) {
4882 if (typeof(p.setActiveItem) !== 'undefined') {
4883 p.setActiveItem(this);
4887 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4888 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4889 // remove the collapsed menu expand...
4890 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4894 isActive: function () {
4897 setActive : function(state, fire, is_was_active)
4899 if (this.active && !state && this.navId) {
4900 this.was_active = true;
4901 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4903 nv.clearWasActive(this);
4907 this.active = state;
4910 this.el.removeClass('active');
4911 this.navLink ? this.navLink.removeClass('active') : false;
4912 } else if (!this.el.hasClass('active')) {
4914 this.el.addClass('active');
4915 if (Roo.bootstrap.version == 4 && this.navLink ) {
4916 this.navLink.addClass('active');
4921 this.fireEvent('changed', this, state);
4924 // show a panel if it's registered and related..
4926 if (!this.navId || !this.tabId || !state || is_was_active) {
4930 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4934 var pan = tg.getPanelByName(this.tabId);
4938 // if we can not flip to new panel - go back to old nav highlight..
4939 if (false == tg.showPanel(pan)) {
4940 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4942 var onav = nv.getWasActive();
4944 onav.setActive(true, false, true);
4953 // this should not be here...
4954 setDisabled : function(state)
4956 this.disabled = state;
4958 this.el.removeClass('disabled');
4959 } else if (!this.el.hasClass('disabled')) {
4960 this.el.addClass('disabled');
4966 * Fetch the element to display the tooltip on.
4967 * @return {Roo.Element} defaults to this.el
4969 tooltipEl : function()
4971 return this.el.select('' + this.tagtype + '', true).first();
4974 scrollToElement : function(e)
4976 var c = document.body;
4979 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4981 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4982 c = document.documentElement;
4985 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4991 var o = target.calcOffsetsTo(c);
4998 this.fireEvent('scrollto', this, options, e);
5000 Roo.get(c).scrollTo('top', options.value, true);
5013 * <span> icon </span>
5014 * <span> text </span>
5015 * <span>badge </span>
5019 * @class Roo.bootstrap.NavSidebarItem
5020 * @extends Roo.bootstrap.NavItem
5021 * Bootstrap Navbar.NavSidebarItem class
5022 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
5023 * {Boolean} open is the menu open
5024 * {Boolean} buttonView use button as the tigger el rather that a (default false)
5025 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
5026 * {String} buttonSize (sm|md|lg)the extra classes for the button
5027 * {Boolean} showArrow show arrow next to the text (default true)
5029 * Create a new Navbar Button
5030 * @param {Object} config The config object
5032 Roo.bootstrap.NavSidebarItem = function(config){
5033 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5038 * The raw click event for the entire grid.
5039 * @param {Roo.EventObject} e
5044 * Fires when the active item active state changes
5045 * @param {Roo.bootstrap.NavSidebarItem} this
5046 * @param {boolean} state the new state
5054 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5056 badgeWeight : 'default',
5062 buttonWeight : 'default',
5068 getAutoCreate : function(){
5073 href : this.href || '#',
5079 if(this.buttonView){
5082 href : this.href || '#',
5083 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5096 cfg.cls += ' active';
5099 if (this.disabled) {
5100 cfg.cls += ' disabled';
5103 cfg.cls += ' open x-open';
5106 if (this.glyphicon || this.icon) {
5107 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5108 a.cn.push({ tag : 'i', cls : c }) ;
5111 if(!this.buttonView){
5114 html : this.html || ''
5121 if (this.badge !== '') {
5122 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5128 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5131 a.cls += ' dropdown-toggle treeview' ;
5137 initEvents : function()
5139 if (typeof (this.menu) != 'undefined') {
5140 this.menu.parentType = this.xtype;
5141 this.menu.triggerEl = this.el;
5142 this.menu = this.addxtype(Roo.apply({}, this.menu));
5145 this.el.on('click', this.onClick, this);
5147 if(this.badge !== ''){
5148 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5153 onClick : function(e)
5160 if(this.preventDefault){
5164 this.fireEvent('click', this, e);
5167 disable : function()
5169 this.setDisabled(true);
5174 this.setDisabled(false);
5177 setDisabled : function(state)
5179 if(this.disabled == state){
5183 this.disabled = state;
5186 this.el.addClass('disabled');
5190 this.el.removeClass('disabled');
5195 setActive : function(state)
5197 if(this.active == state){
5201 this.active = state;
5204 this.el.addClass('active');
5208 this.el.removeClass('active');
5213 isActive: function ()
5218 setBadge : function(str)
5224 this.badgeEl.dom.innerHTML = str;
5241 * @class Roo.bootstrap.Row
5242 * @extends Roo.bootstrap.Component
5243 * Bootstrap Row class (contains columns...)
5247 * @param {Object} config The config object
5250 Roo.bootstrap.Row = function(config){
5251 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5254 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5256 getAutoCreate : function(){
5275 * @class Roo.bootstrap.Element
5276 * @extends Roo.bootstrap.Component
5277 * Bootstrap Element class
5278 * @cfg {String} html contents of the element
5279 * @cfg {String} tag tag of the element
5280 * @cfg {String} cls class of the element
5281 * @cfg {Boolean} preventDefault (true|false) default false
5282 * @cfg {Boolean} clickable (true|false) default false
5285 * Create a new Element
5286 * @param {Object} config The config object
5289 Roo.bootstrap.Element = function(config){
5290 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5296 * When a element is chick
5297 * @param {Roo.bootstrap.Element} this
5298 * @param {Roo.EventObject} e
5304 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5309 preventDefault: false,
5312 getAutoCreate : function(){
5316 // cls: this.cls, double assign in parent class Component.js :: onRender
5323 initEvents: function()
5325 Roo.bootstrap.Element.superclass.initEvents.call(this);
5328 this.el.on('click', this.onClick, this);
5333 onClick : function(e)
5335 if(this.preventDefault){
5339 this.fireEvent('click', this, e);
5342 getValue : function()
5344 return this.el.dom.innerHTML;
5347 setValue : function(value)
5349 this.el.dom.innerHTML = value;
5364 * @class Roo.bootstrap.Pagination
5365 * @extends Roo.bootstrap.Component
5366 * Bootstrap Pagination class
5367 * @cfg {String} size xs | sm | md | lg
5368 * @cfg {Boolean} inverse false | true
5371 * Create a new Pagination
5372 * @param {Object} config The config object
5375 Roo.bootstrap.Pagination = function(config){
5376 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5379 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5385 getAutoCreate : function(){
5391 cfg.cls += ' inverse';
5397 cfg.cls += " " + this.cls;
5415 * @class Roo.bootstrap.PaginationItem
5416 * @extends Roo.bootstrap.Component
5417 * Bootstrap PaginationItem class
5418 * @cfg {String} html text
5419 * @cfg {String} href the link
5420 * @cfg {Boolean} preventDefault (true | false) default true
5421 * @cfg {Boolean} active (true | false) default false
5422 * @cfg {Boolean} disabled default false
5426 * Create a new PaginationItem
5427 * @param {Object} config The config object
5431 Roo.bootstrap.PaginationItem = function(config){
5432 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5437 * The raw click event for the entire grid.
5438 * @param {Roo.EventObject} e
5444 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5448 preventDefault: true,
5453 getAutoCreate : function(){
5459 href : this.href ? this.href : '#',
5460 html : this.html ? this.html : ''
5470 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5474 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5480 initEvents: function() {
5482 this.el.on('click', this.onClick, this);
5485 onClick : function(e)
5487 Roo.log('PaginationItem on click ');
5488 if(this.preventDefault){
5496 this.fireEvent('click', this, e);
5512 * @class Roo.bootstrap.Slider
5513 * @extends Roo.bootstrap.Component
5514 * Bootstrap Slider class
5517 * Create a new Slider
5518 * @param {Object} config The config object
5521 Roo.bootstrap.Slider = function(config){
5522 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5525 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5527 getAutoCreate : function(){
5531 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5535 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5547 * Ext JS Library 1.1.1
5548 * Copyright(c) 2006-2007, Ext JS, LLC.
5550 * Originally Released Under LGPL - original licence link has changed is not relivant.
5553 * <script type="text/javascript">
5558 * @class Roo.grid.ColumnModel
5559 * @extends Roo.util.Observable
5560 * This is the default implementation of a ColumnModel used by the Grid. It defines
5561 * the columns in the grid.
5564 var colModel = new Roo.grid.ColumnModel([
5565 {header: "Ticker", width: 60, sortable: true, locked: true},
5566 {header: "Company Name", width: 150, sortable: true},
5567 {header: "Market Cap.", width: 100, sortable: true},
5568 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5569 {header: "Employees", width: 100, sortable: true, resizable: false}
5574 * The config options listed for this class are options which may appear in each
5575 * individual column definition.
5576 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5578 * @param {Object} config An Array of column config objects. See this class's
5579 * config objects for details.
5581 Roo.grid.ColumnModel = function(config){
5583 * The config passed into the constructor
5585 this.config = config;
5588 // if no id, create one
5589 // if the column does not have a dataIndex mapping,
5590 // map it to the order it is in the config
5591 for(var i = 0, len = config.length; i < len; i++){
5593 if(typeof c.dataIndex == "undefined"){
5596 if(typeof c.renderer == "string"){
5597 c.renderer = Roo.util.Format[c.renderer];
5599 if(typeof c.id == "undefined"){
5602 if(c.editor && c.editor.xtype){
5603 c.editor = Roo.factory(c.editor, Roo.grid);
5605 if(c.editor && c.editor.isFormField){
5606 c.editor = new Roo.grid.GridEditor(c.editor);
5608 this.lookup[c.id] = c;
5612 * The width of columns which have no width specified (defaults to 100)
5615 this.defaultWidth = 100;
5618 * Default sortable of columns which have no sortable specified (defaults to false)
5621 this.defaultSortable = false;
5625 * @event widthchange
5626 * Fires when the width of a column changes.
5627 * @param {ColumnModel} this
5628 * @param {Number} columnIndex The column index
5629 * @param {Number} newWidth The new width
5631 "widthchange": true,
5633 * @event headerchange
5634 * Fires when the text of a header changes.
5635 * @param {ColumnModel} this
5636 * @param {Number} columnIndex The column index
5637 * @param {Number} newText The new header text
5639 "headerchange": true,
5641 * @event hiddenchange
5642 * Fires when a column is hidden or "unhidden".
5643 * @param {ColumnModel} this
5644 * @param {Number} columnIndex The column index
5645 * @param {Boolean} hidden true if hidden, false otherwise
5647 "hiddenchange": true,
5649 * @event columnmoved
5650 * Fires when a column is moved.
5651 * @param {ColumnModel} this
5652 * @param {Number} oldIndex
5653 * @param {Number} newIndex
5655 "columnmoved" : true,
5657 * @event columlockchange
5658 * Fires when a column's locked state is changed
5659 * @param {ColumnModel} this
5660 * @param {Number} colIndex
5661 * @param {Boolean} locked true if locked
5663 "columnlockchange" : true
5665 Roo.grid.ColumnModel.superclass.constructor.call(this);
5667 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5669 * @cfg {String} header The header text to display in the Grid view.
5672 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5673 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5674 * specified, the column's index is used as an index into the Record's data Array.
5677 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5678 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5681 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5682 * Defaults to the value of the {@link #defaultSortable} property.
5683 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5686 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5689 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5692 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5695 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5698 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5699 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5700 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5701 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5704 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5707 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5710 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5713 * @cfg {String} cursor (Optional)
5716 * @cfg {String} tooltip (Optional)
5719 * @cfg {Number} xs (Optional)
5722 * @cfg {Number} sm (Optional)
5725 * @cfg {Number} md (Optional)
5728 * @cfg {Number} lg (Optional)
5731 * Returns the id of the column at the specified index.
5732 * @param {Number} index The column index
5733 * @return {String} the id
5735 getColumnId : function(index){
5736 return this.config[index].id;
5740 * Returns the column for a specified id.
5741 * @param {String} id The column id
5742 * @return {Object} the column
5744 getColumnById : function(id){
5745 return this.lookup[id];
5750 * Returns the column for a specified dataIndex.
5751 * @param {String} dataIndex The column dataIndex
5752 * @return {Object|Boolean} the column or false if not found
5754 getColumnByDataIndex: function(dataIndex){
5755 var index = this.findColumnIndex(dataIndex);
5756 return index > -1 ? this.config[index] : false;
5760 * Returns the index for a specified column id.
5761 * @param {String} id The column id
5762 * @return {Number} the index, or -1 if not found
5764 getIndexById : function(id){
5765 for(var i = 0, len = this.config.length; i < len; i++){
5766 if(this.config[i].id == id){
5774 * Returns the index for a specified column dataIndex.
5775 * @param {String} dataIndex The column dataIndex
5776 * @return {Number} the index, or -1 if not found
5779 findColumnIndex : function(dataIndex){
5780 for(var i = 0, len = this.config.length; i < len; i++){
5781 if(this.config[i].dataIndex == dataIndex){
5789 moveColumn : function(oldIndex, newIndex){
5790 var c = this.config[oldIndex];
5791 this.config.splice(oldIndex, 1);
5792 this.config.splice(newIndex, 0, c);
5793 this.dataMap = null;
5794 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5797 isLocked : function(colIndex){
5798 return this.config[colIndex].locked === true;
5801 setLocked : function(colIndex, value, suppressEvent){
5802 if(this.isLocked(colIndex) == value){
5805 this.config[colIndex].locked = value;
5807 this.fireEvent("columnlockchange", this, colIndex, value);
5811 getTotalLockedWidth : function(){
5813 for(var i = 0; i < this.config.length; i++){
5814 if(this.isLocked(i) && !this.isHidden(i)){
5815 this.totalWidth += this.getColumnWidth(i);
5821 getLockedCount : function(){
5822 for(var i = 0, len = this.config.length; i < len; i++){
5823 if(!this.isLocked(i)){
5828 return this.config.length;
5832 * Returns the number of columns.
5835 getColumnCount : function(visibleOnly){
5836 if(visibleOnly === true){
5838 for(var i = 0, len = this.config.length; i < len; i++){
5839 if(!this.isHidden(i)){
5845 return this.config.length;
5849 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5850 * @param {Function} fn
5851 * @param {Object} scope (optional)
5852 * @return {Array} result
5854 getColumnsBy : function(fn, scope){
5856 for(var i = 0, len = this.config.length; i < len; i++){
5857 var c = this.config[i];
5858 if(fn.call(scope||this, c, i) === true){
5866 * Returns true if the specified column is sortable.
5867 * @param {Number} col The column index
5870 isSortable : function(col){
5871 if(typeof this.config[col].sortable == "undefined"){
5872 return this.defaultSortable;
5874 return this.config[col].sortable;
5878 * Returns the rendering (formatting) function defined for the column.
5879 * @param {Number} col The column index.
5880 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5882 getRenderer : function(col){
5883 if(!this.config[col].renderer){
5884 return Roo.grid.ColumnModel.defaultRenderer;
5886 return this.config[col].renderer;
5890 * Sets the rendering (formatting) function for a column.
5891 * @param {Number} col The column index
5892 * @param {Function} fn The function to use to process the cell's raw data
5893 * to return HTML markup for the grid view. The render function is called with
5894 * the following parameters:<ul>
5895 * <li>Data value.</li>
5896 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5897 * <li>css A CSS style string to apply to the table cell.</li>
5898 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5899 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5900 * <li>Row index</li>
5901 * <li>Column index</li>
5902 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5904 setRenderer : function(col, fn){
5905 this.config[col].renderer = fn;
5909 * Returns the width for the specified column.
5910 * @param {Number} col The column index
5913 getColumnWidth : function(col){
5914 return this.config[col].width * 1 || this.defaultWidth;
5918 * Sets the width for a column.
5919 * @param {Number} col The column index
5920 * @param {Number} width The new width
5922 setColumnWidth : function(col, width, suppressEvent){
5923 this.config[col].width = width;
5924 this.totalWidth = null;
5926 this.fireEvent("widthchange", this, col, width);
5931 * Returns the total width of all columns.
5932 * @param {Boolean} includeHidden True to include hidden column widths
5935 getTotalWidth : function(includeHidden){
5936 if(!this.totalWidth){
5937 this.totalWidth = 0;
5938 for(var i = 0, len = this.config.length; i < len; i++){
5939 if(includeHidden || !this.isHidden(i)){
5940 this.totalWidth += this.getColumnWidth(i);
5944 return this.totalWidth;
5948 * Returns the header for the specified column.
5949 * @param {Number} col The column index
5952 getColumnHeader : function(col){
5953 return this.config[col].header;
5957 * Sets the header for a column.
5958 * @param {Number} col The column index
5959 * @param {String} header The new header
5961 setColumnHeader : function(col, header){
5962 this.config[col].header = header;
5963 this.fireEvent("headerchange", this, col, header);
5967 * Returns the tooltip for the specified column.
5968 * @param {Number} col The column index
5971 getColumnTooltip : function(col){
5972 return this.config[col].tooltip;
5975 * Sets the tooltip for a column.
5976 * @param {Number} col The column index
5977 * @param {String} tooltip The new tooltip
5979 setColumnTooltip : function(col, tooltip){
5980 this.config[col].tooltip = tooltip;
5984 * Returns the dataIndex for the specified column.
5985 * @param {Number} col The column index
5988 getDataIndex : function(col){
5989 return this.config[col].dataIndex;
5993 * Sets the dataIndex for a column.
5994 * @param {Number} col The column index
5995 * @param {Number} dataIndex The new dataIndex
5997 setDataIndex : function(col, dataIndex){
5998 this.config[col].dataIndex = dataIndex;
6004 * Returns true if the cell is editable.
6005 * @param {Number} colIndex The column index
6006 * @param {Number} rowIndex The row index - this is nto actually used..?
6009 isCellEditable : function(colIndex, rowIndex){
6010 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
6014 * Returns the editor defined for the cell/column.
6015 * return false or null to disable editing.
6016 * @param {Number} colIndex The column index
6017 * @param {Number} rowIndex The row index
6020 getCellEditor : function(colIndex, rowIndex){
6021 return this.config[colIndex].editor;
6025 * Sets if a column is editable.
6026 * @param {Number} col The column index
6027 * @param {Boolean} editable True if the column is editable
6029 setEditable : function(col, editable){
6030 this.config[col].editable = editable;
6035 * Returns true if the column is hidden.
6036 * @param {Number} colIndex The column index
6039 isHidden : function(colIndex){
6040 return this.config[colIndex].hidden;
6045 * Returns true if the column width cannot be changed
6047 isFixed : function(colIndex){
6048 return this.config[colIndex].fixed;
6052 * Returns true if the column can be resized
6055 isResizable : function(colIndex){
6056 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6059 * Sets if a column is hidden.
6060 * @param {Number} colIndex The column index
6061 * @param {Boolean} hidden True if the column is hidden
6063 setHidden : function(colIndex, hidden){
6064 this.config[colIndex].hidden = hidden;
6065 this.totalWidth = null;
6066 this.fireEvent("hiddenchange", this, colIndex, hidden);
6070 * Sets the editor for a column.
6071 * @param {Number} col The column index
6072 * @param {Object} editor The editor object
6074 setEditor : function(col, editor){
6075 this.config[col].editor = editor;
6079 Roo.grid.ColumnModel.defaultRenderer = function(value)
6081 if(typeof value == "object") {
6084 if(typeof value == "string" && value.length < 1){
6088 return String.format("{0}", value);
6091 // Alias for backwards compatibility
6092 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6095 * Ext JS Library 1.1.1
6096 * Copyright(c) 2006-2007, Ext JS, LLC.
6098 * Originally Released Under LGPL - original licence link has changed is not relivant.
6101 * <script type="text/javascript">
6105 * @class Roo.LoadMask
6106 * A simple utility class for generically masking elements while loading data. If the element being masked has
6107 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6108 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6109 * element's UpdateManager load indicator and will be destroyed after the initial load.
6111 * Create a new LoadMask
6112 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6113 * @param {Object} config The config object
6115 Roo.LoadMask = function(el, config){
6116 this.el = Roo.get(el);
6117 Roo.apply(this, config);
6119 this.store.on('beforeload', this.onBeforeLoad, this);
6120 this.store.on('load', this.onLoad, this);
6121 this.store.on('loadexception', this.onLoadException, this);
6122 this.removeMask = false;
6124 var um = this.el.getUpdateManager();
6125 um.showLoadIndicator = false; // disable the default indicator
6126 um.on('beforeupdate', this.onBeforeLoad, this);
6127 um.on('update', this.onLoad, this);
6128 um.on('failure', this.onLoad, this);
6129 this.removeMask = true;
6133 Roo.LoadMask.prototype = {
6135 * @cfg {Boolean} removeMask
6136 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6137 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6141 * The text to display in a centered loading message box (defaults to 'Loading...')
6145 * @cfg {String} msgCls
6146 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6148 msgCls : 'x-mask-loading',
6151 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6157 * Disables the mask to prevent it from being displayed
6159 disable : function(){
6160 this.disabled = true;
6164 * Enables the mask so that it can be displayed
6166 enable : function(){
6167 this.disabled = false;
6170 onLoadException : function()
6174 if (typeof(arguments[3]) != 'undefined') {
6175 Roo.MessageBox.alert("Error loading",arguments[3]);
6179 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6180 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6187 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6192 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6196 onBeforeLoad : function(){
6198 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6203 destroy : function(){
6205 this.store.un('beforeload', this.onBeforeLoad, this);
6206 this.store.un('load', this.onLoad, this);
6207 this.store.un('loadexception', this.onLoadException, this);
6209 var um = this.el.getUpdateManager();
6210 um.un('beforeupdate', this.onBeforeLoad, this);
6211 um.un('update', this.onLoad, this);
6212 um.un('failure', this.onLoad, this);
6223 * @class Roo.bootstrap.Table
6224 * @extends Roo.bootstrap.Component
6225 * Bootstrap Table class
6226 * @cfg {String} cls table class
6227 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6228 * @cfg {String} bgcolor Specifies the background color for a table
6229 * @cfg {Number} border Specifies whether the table cells should have borders or not
6230 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6231 * @cfg {Number} cellspacing Specifies the space between cells
6232 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6233 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6234 * @cfg {String} sortable Specifies that the table should be sortable
6235 * @cfg {String} summary Specifies a summary of the content of a table
6236 * @cfg {Number} width Specifies the width of a table
6237 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6239 * @cfg {boolean} striped Should the rows be alternative striped
6240 * @cfg {boolean} bordered Add borders to the table
6241 * @cfg {boolean} hover Add hover highlighting
6242 * @cfg {boolean} condensed Format condensed
6243 * @cfg {boolean} responsive Format condensed
6244 * @cfg {Boolean} loadMask (true|false) default false
6245 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6246 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6247 * @cfg {Boolean} rowSelection (true|false) default false
6248 * @cfg {Boolean} cellSelection (true|false) default false
6249 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6250 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6251 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6252 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6256 * Create a new Table
6257 * @param {Object} config The config object
6260 Roo.bootstrap.Table = function(config){
6261 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6266 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6267 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6268 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6269 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6271 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6273 this.sm.grid = this;
6274 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6275 this.sm = this.selModel;
6276 this.sm.xmodule = this.xmodule || false;
6279 if (this.cm && typeof(this.cm.config) == 'undefined') {
6280 this.colModel = new Roo.grid.ColumnModel(this.cm);
6281 this.cm = this.colModel;
6282 this.cm.xmodule = this.xmodule || false;
6285 this.store= Roo.factory(this.store, Roo.data);
6286 this.ds = this.store;
6287 this.ds.xmodule = this.xmodule || false;
6290 if (this.footer && this.store) {
6291 this.footer.dataSource = this.ds;
6292 this.footer = Roo.factory(this.footer);
6299 * Fires when a cell is clicked
6300 * @param {Roo.bootstrap.Table} this
6301 * @param {Roo.Element} el
6302 * @param {Number} rowIndex
6303 * @param {Number} columnIndex
6304 * @param {Roo.EventObject} e
6308 * @event celldblclick
6309 * Fires when a cell is double clicked
6310 * @param {Roo.bootstrap.Table} this
6311 * @param {Roo.Element} el
6312 * @param {Number} rowIndex
6313 * @param {Number} columnIndex
6314 * @param {Roo.EventObject} e
6316 "celldblclick" : true,
6319 * Fires when a row is clicked
6320 * @param {Roo.bootstrap.Table} this
6321 * @param {Roo.Element} el
6322 * @param {Number} rowIndex
6323 * @param {Roo.EventObject} e
6327 * @event rowdblclick
6328 * Fires when a row is double clicked
6329 * @param {Roo.bootstrap.Table} this
6330 * @param {Roo.Element} el
6331 * @param {Number} rowIndex
6332 * @param {Roo.EventObject} e
6334 "rowdblclick" : true,
6337 * Fires when a mouseover occur
6338 * @param {Roo.bootstrap.Table} this
6339 * @param {Roo.Element} el
6340 * @param {Number} rowIndex
6341 * @param {Number} columnIndex
6342 * @param {Roo.EventObject} e
6347 * Fires when a mouseout occur
6348 * @param {Roo.bootstrap.Table} this
6349 * @param {Roo.Element} el
6350 * @param {Number} rowIndex
6351 * @param {Number} columnIndex
6352 * @param {Roo.EventObject} e
6357 * Fires when a row is rendered, so you can change add a style to it.
6358 * @param {Roo.bootstrap.Table} this
6359 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6363 * @event rowsrendered
6364 * Fires when all the rows have been rendered
6365 * @param {Roo.bootstrap.Table} this
6367 'rowsrendered' : true,
6369 * @event contextmenu
6370 * The raw contextmenu event for the entire grid.
6371 * @param {Roo.EventObject} e
6373 "contextmenu" : true,
6375 * @event rowcontextmenu
6376 * Fires when a row is right clicked
6377 * @param {Roo.bootstrap.Table} this
6378 * @param {Number} rowIndex
6379 * @param {Roo.EventObject} e
6381 "rowcontextmenu" : true,
6383 * @event cellcontextmenu
6384 * Fires when a cell is right clicked
6385 * @param {Roo.bootstrap.Table} this
6386 * @param {Number} rowIndex
6387 * @param {Number} cellIndex
6388 * @param {Roo.EventObject} e
6390 "cellcontextmenu" : true,
6392 * @event headercontextmenu
6393 * Fires when a header is right clicked
6394 * @param {Roo.bootstrap.Table} this
6395 * @param {Number} columnIndex
6396 * @param {Roo.EventObject} e
6398 "headercontextmenu" : true
6402 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6428 rowSelection : false,
6429 cellSelection : false,
6432 // Roo.Element - the tbody
6434 // Roo.Element - thead element
6437 container: false, // used by gridpanel...
6443 auto_hide_footer : false,
6445 getAutoCreate : function()
6447 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6454 if (this.scrollBody) {
6455 cfg.cls += ' table-body-fixed';
6458 cfg.cls += ' table-striped';
6462 cfg.cls += ' table-hover';
6464 if (this.bordered) {
6465 cfg.cls += ' table-bordered';
6467 if (this.condensed) {
6468 cfg.cls += ' table-condensed';
6470 if (this.responsive) {
6471 cfg.cls += ' table-responsive';
6475 cfg.cls+= ' ' +this.cls;
6478 // this lot should be simplifed...
6491 ].forEach(function(k) {
6499 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6502 if(this.store || this.cm){
6503 if(this.headerShow){
6504 cfg.cn.push(this.renderHeader());
6507 cfg.cn.push(this.renderBody());
6509 if(this.footerShow){
6510 cfg.cn.push(this.renderFooter());
6512 // where does this come from?
6513 //cfg.cls+= ' TableGrid';
6516 return { cn : [ cfg ] };
6519 initEvents : function()
6521 if(!this.store || !this.cm){
6524 if (this.selModel) {
6525 this.selModel.initEvents();
6529 //Roo.log('initEvents with ds!!!!');
6531 this.mainBody = this.el.select('tbody', true).first();
6532 this.mainHead = this.el.select('thead', true).first();
6533 this.mainFoot = this.el.select('tfoot', true).first();
6539 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6540 e.on('click', _this.sort, _this);
6543 this.mainBody.on("click", this.onClick, this);
6544 this.mainBody.on("dblclick", this.onDblClick, this);
6546 // why is this done????? = it breaks dialogs??
6547 //this.parent().el.setStyle('position', 'relative');
6551 this.footer.parentId = this.id;
6552 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6555 this.el.select('tfoot tr td').first().addClass('hide');
6560 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6563 this.store.on('load', this.onLoad, this);
6564 this.store.on('beforeload', this.onBeforeLoad, this);
6565 this.store.on('update', this.onUpdate, this);
6566 this.store.on('add', this.onAdd, this);
6567 this.store.on("clear", this.clear, this);
6569 this.el.on("contextmenu", this.onContextMenu, this);
6571 this.mainBody.on('scroll', this.onBodyScroll, this);
6573 this.cm.on("headerchange", this.onHeaderChange, this);
6575 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6579 onContextMenu : function(e, t)
6581 this.processEvent("contextmenu", e);
6584 processEvent : function(name, e)
6586 if (name != 'touchstart' ) {
6587 this.fireEvent(name, e);
6590 var t = e.getTarget();
6592 var cell = Roo.get(t);
6598 if(cell.findParent('tfoot', false, true)){
6602 if(cell.findParent('thead', false, true)){
6604 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6605 cell = Roo.get(t).findParent('th', false, true);
6607 Roo.log("failed to find th in thead?");
6608 Roo.log(e.getTarget());
6613 var cellIndex = cell.dom.cellIndex;
6615 var ename = name == 'touchstart' ? 'click' : name;
6616 this.fireEvent("header" + ename, this, cellIndex, e);
6621 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6622 cell = Roo.get(t).findParent('td', false, true);
6624 Roo.log("failed to find th in tbody?");
6625 Roo.log(e.getTarget());
6630 var row = cell.findParent('tr', false, true);
6631 var cellIndex = cell.dom.cellIndex;
6632 var rowIndex = row.dom.rowIndex - 1;
6636 this.fireEvent("row" + name, this, rowIndex, e);
6640 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6646 onMouseover : function(e, el)
6648 var cell = Roo.get(el);
6654 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6655 cell = cell.findParent('td', false, true);
6658 var row = cell.findParent('tr', false, true);
6659 var cellIndex = cell.dom.cellIndex;
6660 var rowIndex = row.dom.rowIndex - 1; // start from 0
6662 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6666 onMouseout : function(e, el)
6668 var cell = Roo.get(el);
6674 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6675 cell = cell.findParent('td', false, true);
6678 var row = cell.findParent('tr', false, true);
6679 var cellIndex = cell.dom.cellIndex;
6680 var rowIndex = row.dom.rowIndex - 1; // start from 0
6682 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6686 onClick : function(e, el)
6688 var cell = Roo.get(el);
6690 if(!cell || (!this.cellSelection && !this.rowSelection)){
6694 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6695 cell = cell.findParent('td', false, true);
6698 if(!cell || typeof(cell) == 'undefined'){
6702 var row = cell.findParent('tr', false, true);
6704 if(!row || typeof(row) == 'undefined'){
6708 var cellIndex = cell.dom.cellIndex;
6709 var rowIndex = this.getRowIndex(row);
6711 // why??? - should these not be based on SelectionModel?
6712 if(this.cellSelection){
6713 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6716 if(this.rowSelection){
6717 this.fireEvent('rowclick', this, row, rowIndex, e);
6723 onDblClick : function(e,el)
6725 var cell = Roo.get(el);
6727 if(!cell || (!this.cellSelection && !this.rowSelection)){
6731 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6732 cell = cell.findParent('td', false, true);
6735 if(!cell || typeof(cell) == 'undefined'){
6739 var row = cell.findParent('tr', false, true);
6741 if(!row || typeof(row) == 'undefined'){
6745 var cellIndex = cell.dom.cellIndex;
6746 var rowIndex = this.getRowIndex(row);
6748 if(this.cellSelection){
6749 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6752 if(this.rowSelection){
6753 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6757 sort : function(e,el)
6759 var col = Roo.get(el);
6761 if(!col.hasClass('sortable')){
6765 var sort = col.attr('sort');
6768 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6772 this.store.sortInfo = {field : sort, direction : dir};
6775 Roo.log("calling footer first");
6776 this.footer.onClick('first');
6779 this.store.load({ params : { start : 0 } });
6783 renderHeader : function()
6791 this.totalWidth = 0;
6793 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6795 var config = cm.config[i];
6799 cls : 'x-hcol-' + i,
6801 html: cm.getColumnHeader(i)
6806 if(typeof(config.sortable) != 'undefined' && config.sortable){
6808 c.html = '<i class="glyphicon"></i>' + c.html;
6811 if(typeof(config.lgHeader) != 'undefined'){
6812 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6815 if(typeof(config.mdHeader) != 'undefined'){
6816 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6819 if(typeof(config.smHeader) != 'undefined'){
6820 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6823 if(typeof(config.xsHeader) != 'undefined'){
6824 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6831 if(typeof(config.tooltip) != 'undefined'){
6832 c.tooltip = config.tooltip;
6835 if(typeof(config.colspan) != 'undefined'){
6836 c.colspan = config.colspan;
6839 if(typeof(config.hidden) != 'undefined' && config.hidden){
6840 c.style += ' display:none;';
6843 if(typeof(config.dataIndex) != 'undefined'){
6844 c.sort = config.dataIndex;
6849 if(typeof(config.align) != 'undefined' && config.align.length){
6850 c.style += ' text-align:' + config.align + ';';
6853 if(typeof(config.width) != 'undefined'){
6854 c.style += ' width:' + config.width + 'px;';
6855 this.totalWidth += config.width;
6857 this.totalWidth += 100; // assume minimum of 100 per column?
6860 if(typeof(config.cls) != 'undefined'){
6861 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6864 ['xs','sm','md','lg'].map(function(size){
6866 if(typeof(config[size]) == 'undefined'){
6870 if (!config[size]) { // 0 = hidden
6871 // BS 4 '0' is treated as hide that column and below.
6872 c.cls += ' hidden-' + size + ' hidden' + size + 'down';
6876 c.cls += ' col-' + size + '-' + config[size] + (
6877 size == 'xs' ? (' col-' + + config[size] ) : '' // bs4 col-{num} replaces col-xs
6889 renderBody : function()
6899 colspan : this.cm.getColumnCount()
6909 renderFooter : function()
6919 colspan : this.cm.getColumnCount()
6933 // Roo.log('ds onload');
6938 var ds = this.store;
6940 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6941 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6942 if (_this.store.sortInfo) {
6944 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6945 e.select('i', true).addClass(['glyphicon-arrow-up']);
6948 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6949 e.select('i', true).addClass(['glyphicon-arrow-down']);
6954 var tbody = this.mainBody;
6956 if(ds.getCount() > 0){
6957 ds.data.each(function(d,rowIndex){
6958 var row = this.renderRow(cm, ds, rowIndex);
6960 tbody.createChild(row);
6964 if(row.cellObjects.length){
6965 Roo.each(row.cellObjects, function(r){
6966 _this.renderCellObject(r);
6973 var tfoot = this.el.select('tfoot', true).first();
6975 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6977 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6979 var total = this.ds.getTotalCount();
6981 if(this.footer.pageSize < total){
6982 this.mainFoot.show();
6986 Roo.each(this.el.select('tbody td', true).elements, function(e){
6987 e.on('mouseover', _this.onMouseover, _this);
6990 Roo.each(this.el.select('tbody td', true).elements, function(e){
6991 e.on('mouseout', _this.onMouseout, _this);
6993 this.fireEvent('rowsrendered', this);
6999 onUpdate : function(ds,record)
7001 this.refreshRow(record);
7005 onRemove : function(ds, record, index, isUpdate){
7006 if(isUpdate !== true){
7007 this.fireEvent("beforerowremoved", this, index, record);
7009 var bt = this.mainBody.dom;
7011 var rows = this.el.select('tbody > tr', true).elements;
7013 if(typeof(rows[index]) != 'undefined'){
7014 bt.removeChild(rows[index].dom);
7017 // if(bt.rows[index]){
7018 // bt.removeChild(bt.rows[index]);
7021 if(isUpdate !== true){
7022 //this.stripeRows(index);
7023 //this.syncRowHeights(index, index);
7025 this.fireEvent("rowremoved", this, index, record);
7029 onAdd : function(ds, records, rowIndex)
7031 //Roo.log('on Add called');
7032 // - note this does not handle multiple adding very well..
7033 var bt = this.mainBody.dom;
7034 for (var i =0 ; i < records.length;i++) {
7035 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
7036 //Roo.log(records[i]);
7037 //Roo.log(this.store.getAt(rowIndex+i));
7038 this.insertRow(this.store, rowIndex + i, false);
7045 refreshRow : function(record){
7046 var ds = this.store, index;
7047 if(typeof record == 'number'){
7049 record = ds.getAt(index);
7051 index = ds.indexOf(record);
7053 this.insertRow(ds, index, true);
7055 this.onRemove(ds, record, index+1, true);
7057 //this.syncRowHeights(index, index);
7059 this.fireEvent("rowupdated", this, index, record);
7062 insertRow : function(dm, rowIndex, isUpdate){
7065 this.fireEvent("beforerowsinserted", this, rowIndex);
7067 //var s = this.getScrollState();
7068 var row = this.renderRow(this.cm, this.store, rowIndex);
7069 // insert before rowIndex..
7070 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7074 if(row.cellObjects.length){
7075 Roo.each(row.cellObjects, function(r){
7076 _this.renderCellObject(r);
7081 this.fireEvent("rowsinserted", this, rowIndex);
7082 //this.syncRowHeights(firstRow, lastRow);
7083 //this.stripeRows(firstRow);
7090 getRowDom : function(rowIndex)
7092 var rows = this.el.select('tbody > tr', true).elements;
7094 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7097 // returns the object tree for a tr..
7100 renderRow : function(cm, ds, rowIndex)
7102 var d = ds.getAt(rowIndex);
7106 cls : 'x-row-' + rowIndex,
7110 var cellObjects = [];
7112 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7113 var config = cm.config[i];
7115 var renderer = cm.getRenderer(i);
7119 if(typeof(renderer) !== 'undefined'){
7120 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7122 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7123 // and are rendered into the cells after the row is rendered - using the id for the element.
7125 if(typeof(value) === 'object'){
7135 rowIndex : rowIndex,
7140 this.fireEvent('rowclass', this, rowcfg);
7144 cls : rowcfg.rowClass + ' x-col-' + i,
7146 html: (typeof(value) === 'object') ? '' : value
7153 if(typeof(config.colspan) != 'undefined'){
7154 td.colspan = config.colspan;
7157 if(typeof(config.hidden) != 'undefined' && config.hidden){
7158 td.style += ' display:none;';
7161 if(typeof(config.align) != 'undefined' && config.align.length){
7162 td.style += ' text-align:' + config.align + ';';
7164 if(typeof(config.valign) != 'undefined' && config.valign.length){
7165 td.style += ' vertical-align:' + config.valign + ';';
7168 if(typeof(config.width) != 'undefined'){
7169 td.style += ' width:' + config.width + 'px;';
7172 if(typeof(config.cursor) != 'undefined'){
7173 td.style += ' cursor:' + config.cursor + ';';
7176 if(typeof(config.cls) != 'undefined'){
7177 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7180 ['xs','sm','md','lg'].map(function(size){
7182 if(typeof(config[size]) == 'undefined'){
7186 if (!config[size]) { // 0 = hidden
7187 td.cls += ' hidden-' + size;
7191 td.cls += ' col-' + size + '-' + config[size];
7199 row.cellObjects = cellObjects;
7207 onBeforeLoad : function()
7216 this.el.select('tbody', true).first().dom.innerHTML = '';
7219 * Show or hide a row.
7220 * @param {Number} rowIndex to show or hide
7221 * @param {Boolean} state hide
7223 setRowVisibility : function(rowIndex, state)
7225 var bt = this.mainBody.dom;
7227 var rows = this.el.select('tbody > tr', true).elements;
7229 if(typeof(rows[rowIndex]) == 'undefined'){
7232 rows[rowIndex].dom.style.display = state ? '' : 'none';
7236 getSelectionModel : function(){
7238 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7240 return this.selModel;
7243 * Render the Roo.bootstrap object from renderder
7245 renderCellObject : function(r)
7249 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7251 var t = r.cfg.render(r.container);
7254 Roo.each(r.cfg.cn, function(c){
7256 container: t.getChildContainer(),
7259 _this.renderCellObject(child);
7264 getRowIndex : function(row)
7268 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7279 * Returns the grid's underlying element = used by panel.Grid
7280 * @return {Element} The element
7282 getGridEl : function(){
7286 * Forces a resize - used by panel.Grid
7287 * @return {Element} The element
7289 autoSize : function()
7291 //var ctr = Roo.get(this.container.dom.parentElement);
7292 var ctr = Roo.get(this.el.dom);
7294 var thd = this.getGridEl().select('thead',true).first();
7295 var tbd = this.getGridEl().select('tbody', true).first();
7296 var tfd = this.getGridEl().select('tfoot', true).first();
7298 var cw = ctr.getWidth();
7302 tbd.setSize(ctr.getWidth(),
7303 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7305 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7308 cw = Math.max(cw, this.totalWidth);
7309 this.getGridEl().select('tr',true).setWidth(cw);
7310 // resize 'expandable coloumn?
7312 return; // we doe not have a view in this design..
7315 onBodyScroll: function()
7317 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7319 this.mainHead.setStyle({
7320 'position' : 'relative',
7321 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7327 var scrollHeight = this.mainBody.dom.scrollHeight;
7329 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7331 var height = this.mainBody.getHeight();
7333 if(scrollHeight - height == scrollTop) {
7335 var total = this.ds.getTotalCount();
7337 if(this.footer.cursor + this.footer.pageSize < total){
7339 this.footer.ds.load({
7341 start : this.footer.cursor + this.footer.pageSize,
7342 limit : this.footer.pageSize
7352 onHeaderChange : function()
7354 var header = this.renderHeader();
7355 var table = this.el.select('table', true).first();
7357 this.mainHead.remove();
7358 this.mainHead = table.createChild(header, this.mainBody, false);
7361 onHiddenChange : function(colModel, colIndex, hidden)
7363 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7364 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7366 this.CSS.updateRule(thSelector, "display", "");
7367 this.CSS.updateRule(tdSelector, "display", "");
7370 this.CSS.updateRule(thSelector, "display", "none");
7371 this.CSS.updateRule(tdSelector, "display", "none");
7374 this.onHeaderChange();
7378 setColumnWidth: function(col_index, width)
7380 // width = "md-2 xs-2..."
7381 if(!this.colModel.config[col_index]) {
7385 var w = width.split(" ");
7387 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7389 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7392 for(var j = 0; j < w.length; j++) {
7398 var size_cls = w[j].split("-");
7400 if(!Number.isInteger(size_cls[1] * 1)) {
7404 if(!this.colModel.config[col_index][size_cls[0]]) {
7408 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7412 h_row[0].classList.replace(
7413 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7414 "col-"+size_cls[0]+"-"+size_cls[1]
7417 for(var i = 0; i < rows.length; i++) {
7419 var size_cls = w[j].split("-");
7421 if(!Number.isInteger(size_cls[1] * 1)) {
7425 if(!this.colModel.config[col_index][size_cls[0]]) {
7429 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7433 rows[i].classList.replace(
7434 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7435 "col-"+size_cls[0]+"-"+size_cls[1]
7439 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7454 * @class Roo.bootstrap.TableCell
7455 * @extends Roo.bootstrap.Component
7456 * Bootstrap TableCell class
7457 * @cfg {String} html cell contain text
7458 * @cfg {String} cls cell class
7459 * @cfg {String} tag cell tag (td|th) default td
7460 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7461 * @cfg {String} align Aligns the content in a cell
7462 * @cfg {String} axis Categorizes cells
7463 * @cfg {String} bgcolor Specifies the background color of a cell
7464 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7465 * @cfg {Number} colspan Specifies the number of columns a cell should span
7466 * @cfg {String} headers Specifies one or more header cells a cell is related to
7467 * @cfg {Number} height Sets the height of a cell
7468 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7469 * @cfg {Number} rowspan Sets the number of rows a cell should span
7470 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7471 * @cfg {String} valign Vertical aligns the content in a cell
7472 * @cfg {Number} width Specifies the width of a cell
7475 * Create a new TableCell
7476 * @param {Object} config The config object
7479 Roo.bootstrap.TableCell = function(config){
7480 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7483 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7503 getAutoCreate : function(){
7504 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7524 cfg.align=this.align
7530 cfg.bgcolor=this.bgcolor
7533 cfg.charoff=this.charoff
7536 cfg.colspan=this.colspan
7539 cfg.headers=this.headers
7542 cfg.height=this.height
7545 cfg.nowrap=this.nowrap
7548 cfg.rowspan=this.rowspan
7551 cfg.scope=this.scope
7554 cfg.valign=this.valign
7557 cfg.width=this.width
7576 * @class Roo.bootstrap.TableRow
7577 * @extends Roo.bootstrap.Component
7578 * Bootstrap TableRow class
7579 * @cfg {String} cls row class
7580 * @cfg {String} align Aligns the content in a table row
7581 * @cfg {String} bgcolor Specifies a background color for a table row
7582 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7583 * @cfg {String} valign Vertical aligns the content in a table row
7586 * Create a new TableRow
7587 * @param {Object} config The config object
7590 Roo.bootstrap.TableRow = function(config){
7591 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7594 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7602 getAutoCreate : function(){
7603 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7613 cfg.align = this.align;
7616 cfg.bgcolor = this.bgcolor;
7619 cfg.charoff = this.charoff;
7622 cfg.valign = this.valign;
7640 * @class Roo.bootstrap.TableBody
7641 * @extends Roo.bootstrap.Component
7642 * Bootstrap TableBody class
7643 * @cfg {String} cls element class
7644 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7645 * @cfg {String} align Aligns the content inside the element
7646 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7647 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7650 * Create a new TableBody
7651 * @param {Object} config The config object
7654 Roo.bootstrap.TableBody = function(config){
7655 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7658 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7666 getAutoCreate : function(){
7667 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7681 cfg.align = this.align;
7684 cfg.charoff = this.charoff;
7687 cfg.valign = this.valign;
7694 // initEvents : function()
7701 // this.store = Roo.factory(this.store, Roo.data);
7702 // this.store.on('load', this.onLoad, this);
7704 // this.store.load();
7708 // onLoad: function ()
7710 // this.fireEvent('load', this);
7720 * Ext JS Library 1.1.1
7721 * Copyright(c) 2006-2007, Ext JS, LLC.
7723 * Originally Released Under LGPL - original licence link has changed is not relivant.
7726 * <script type="text/javascript">
7729 // as we use this in bootstrap.
7730 Roo.namespace('Roo.form');
7732 * @class Roo.form.Action
7733 * Internal Class used to handle form actions
7735 * @param {Roo.form.BasicForm} el The form element or its id
7736 * @param {Object} config Configuration options
7741 // define the action interface
7742 Roo.form.Action = function(form, options){
7744 this.options = options || {};
7747 * Client Validation Failed
7750 Roo.form.Action.CLIENT_INVALID = 'client';
7752 * Server Validation Failed
7755 Roo.form.Action.SERVER_INVALID = 'server';
7757 * Connect to Server Failed
7760 Roo.form.Action.CONNECT_FAILURE = 'connect';
7762 * Reading Data from Server Failed
7765 Roo.form.Action.LOAD_FAILURE = 'load';
7767 Roo.form.Action.prototype = {
7769 failureType : undefined,
7770 response : undefined,
7774 run : function(options){
7779 success : function(response){
7784 handleResponse : function(response){
7788 // default connection failure
7789 failure : function(response){
7791 this.response = response;
7792 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7793 this.form.afterAction(this, false);
7796 processResponse : function(response){
7797 this.response = response;
7798 if(!response.responseText){
7801 this.result = this.handleResponse(response);
7805 // utility functions used internally
7806 getUrl : function(appendParams){
7807 var url = this.options.url || this.form.url || this.form.el.dom.action;
7809 var p = this.getParams();
7811 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7817 getMethod : function(){
7818 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7821 getParams : function(){
7822 var bp = this.form.baseParams;
7823 var p = this.options.params;
7825 if(typeof p == "object"){
7826 p = Roo.urlEncode(Roo.applyIf(p, bp));
7827 }else if(typeof p == 'string' && bp){
7828 p += '&' + Roo.urlEncode(bp);
7831 p = Roo.urlEncode(bp);
7836 createCallback : function(){
7838 success: this.success,
7839 failure: this.failure,
7841 timeout: (this.form.timeout*1000),
7842 upload: this.form.fileUpload ? this.success : undefined
7847 Roo.form.Action.Submit = function(form, options){
7848 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7851 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7854 haveProgress : false,
7855 uploadComplete : false,
7857 // uploadProgress indicator.
7858 uploadProgress : function()
7860 if (!this.form.progressUrl) {
7864 if (!this.haveProgress) {
7865 Roo.MessageBox.progress("Uploading", "Uploading");
7867 if (this.uploadComplete) {
7868 Roo.MessageBox.hide();
7872 this.haveProgress = true;
7874 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7876 var c = new Roo.data.Connection();
7878 url : this.form.progressUrl,
7883 success : function(req){
7884 //console.log(data);
7888 rdata = Roo.decode(req.responseText)
7890 Roo.log("Invalid data from server..");
7894 if (!rdata || !rdata.success) {
7896 Roo.MessageBox.alert(Roo.encode(rdata));
7899 var data = rdata.data;
7901 if (this.uploadComplete) {
7902 Roo.MessageBox.hide();
7907 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7908 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7911 this.uploadProgress.defer(2000,this);
7914 failure: function(data) {
7915 Roo.log('progress url failed ');
7926 // run get Values on the form, so it syncs any secondary forms.
7927 this.form.getValues();
7929 var o = this.options;
7930 var method = this.getMethod();
7931 var isPost = method == 'POST';
7932 if(o.clientValidation === false || this.form.isValid()){
7934 if (this.form.progressUrl) {
7935 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7936 (new Date() * 1) + '' + Math.random());
7941 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7942 form:this.form.el.dom,
7943 url:this.getUrl(!isPost),
7945 params:isPost ? this.getParams() : null,
7946 isUpload: this.form.fileUpload,
7947 formData : this.form.formData
7950 this.uploadProgress();
7952 }else if (o.clientValidation !== false){ // client validation failed
7953 this.failureType = Roo.form.Action.CLIENT_INVALID;
7954 this.form.afterAction(this, false);
7958 success : function(response)
7960 this.uploadComplete= true;
7961 if (this.haveProgress) {
7962 Roo.MessageBox.hide();
7966 var result = this.processResponse(response);
7967 if(result === true || result.success){
7968 this.form.afterAction(this, true);
7972 this.form.markInvalid(result.errors);
7973 this.failureType = Roo.form.Action.SERVER_INVALID;
7975 this.form.afterAction(this, false);
7977 failure : function(response)
7979 this.uploadComplete= true;
7980 if (this.haveProgress) {
7981 Roo.MessageBox.hide();
7984 this.response = response;
7985 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7986 this.form.afterAction(this, false);
7989 handleResponse : function(response){
7990 if(this.form.errorReader){
7991 var rs = this.form.errorReader.read(response);
7994 for(var i = 0, len = rs.records.length; i < len; i++) {
7995 var r = rs.records[i];
7999 if(errors.length < 1){
8003 success : rs.success,
8009 ret = Roo.decode(response.responseText);
8013 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
8023 Roo.form.Action.Load = function(form, options){
8024 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
8025 this.reader = this.form.reader;
8028 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
8033 Roo.Ajax.request(Roo.apply(
8034 this.createCallback(), {
8035 method:this.getMethod(),
8036 url:this.getUrl(false),
8037 params:this.getParams()
8041 success : function(response){
8043 var result = this.processResponse(response);
8044 if(result === true || !result.success || !result.data){
8045 this.failureType = Roo.form.Action.LOAD_FAILURE;
8046 this.form.afterAction(this, false);
8049 this.form.clearInvalid();
8050 this.form.setValues(result.data);
8051 this.form.afterAction(this, true);
8054 handleResponse : function(response){
8055 if(this.form.reader){
8056 var rs = this.form.reader.read(response);
8057 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8059 success : rs.success,
8063 return Roo.decode(response.responseText);
8067 Roo.form.Action.ACTION_TYPES = {
8068 'load' : Roo.form.Action.Load,
8069 'submit' : Roo.form.Action.Submit
8078 * @class Roo.bootstrap.Form
8079 * @extends Roo.bootstrap.Component
8080 * Bootstrap Form class
8081 * @cfg {String} method GET | POST (default POST)
8082 * @cfg {String} labelAlign top | left (default top)
8083 * @cfg {String} align left | right - for navbars
8084 * @cfg {Boolean} loadMask load mask when submit (default true)
8089 * @param {Object} config The config object
8093 Roo.bootstrap.Form = function(config){
8095 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8097 Roo.bootstrap.Form.popover.apply();
8101 * @event clientvalidation
8102 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8103 * @param {Form} this
8104 * @param {Boolean} valid true if the form has passed client-side validation
8106 clientvalidation: true,
8108 * @event beforeaction
8109 * Fires before any action is performed. Return false to cancel the action.
8110 * @param {Form} this
8111 * @param {Action} action The action to be performed
8115 * @event actionfailed
8116 * Fires when an action fails.
8117 * @param {Form} this
8118 * @param {Action} action The action that failed
8120 actionfailed : true,
8122 * @event actioncomplete
8123 * Fires when an action is completed.
8124 * @param {Form} this
8125 * @param {Action} action The action that completed
8127 actioncomplete : true
8131 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8134 * @cfg {String} method
8135 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8140 * The URL to use for form actions if one isn't supplied in the action options.
8143 * @cfg {Boolean} fileUpload
8144 * Set to true if this form is a file upload.
8148 * @cfg {Object} baseParams
8149 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8153 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8157 * @cfg {Sting} align (left|right) for navbar forms
8162 activeAction : null,
8165 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8166 * element by passing it or its id or mask the form itself by passing in true.
8169 waitMsgTarget : false,
8174 * @cfg {Boolean} errorMask (true|false) default false
8179 * @cfg {Number} maskOffset Default 100
8184 * @cfg {Boolean} maskBody
8188 getAutoCreate : function(){
8192 method : this.method || 'POST',
8193 id : this.id || Roo.id(),
8196 if (this.parent().xtype.match(/^Nav/)) {
8197 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8201 if (this.labelAlign == 'left' ) {
8202 cfg.cls += ' form-horizontal';
8208 initEvents : function()
8210 this.el.on('submit', this.onSubmit, this);
8211 // this was added as random key presses on the form where triggering form submit.
8212 this.el.on('keypress', function(e) {
8213 if (e.getCharCode() != 13) {
8216 // we might need to allow it for textareas.. and some other items.
8217 // check e.getTarget().
8219 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8223 Roo.log("keypress blocked");
8231 onSubmit : function(e){
8236 * Returns true if client-side validation on the form is successful.
8239 isValid : function(){
8240 var items = this.getItems();
8244 items.each(function(f){
8250 Roo.log('invalid field: ' + f.name);
8254 if(!target && f.el.isVisible(true)){
8260 if(this.errorMask && !valid){
8261 Roo.bootstrap.Form.popover.mask(this, target);
8268 * Returns true if any fields in this form have changed since their original load.
8271 isDirty : function(){
8273 var items = this.getItems();
8274 items.each(function(f){
8284 * Performs a predefined action (submit or load) or custom actions you define on this form.
8285 * @param {String} actionName The name of the action type
8286 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8287 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8288 * accept other config options):
8290 Property Type Description
8291 ---------------- --------------- ----------------------------------------------------------------------------------
8292 url String The url for the action (defaults to the form's url)
8293 method String The form method to use (defaults to the form's method, or POST if not defined)
8294 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8295 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8296 validate the form on the client (defaults to false)
8298 * @return {BasicForm} this
8300 doAction : function(action, options){
8301 if(typeof action == 'string'){
8302 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8304 if(this.fireEvent('beforeaction', this, action) !== false){
8305 this.beforeAction(action);
8306 action.run.defer(100, action);
8312 beforeAction : function(action){
8313 var o = action.options;
8318 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8320 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8323 // not really supported yet.. ??
8325 //if(this.waitMsgTarget === true){
8326 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8327 //}else if(this.waitMsgTarget){
8328 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8329 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8331 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8337 afterAction : function(action, success){
8338 this.activeAction = null;
8339 var o = action.options;
8344 Roo.get(document.body).unmask();
8350 //if(this.waitMsgTarget === true){
8351 // this.el.unmask();
8352 //}else if(this.waitMsgTarget){
8353 // this.waitMsgTarget.unmask();
8355 // Roo.MessageBox.updateProgress(1);
8356 // Roo.MessageBox.hide();
8363 Roo.callback(o.success, o.scope, [this, action]);
8364 this.fireEvent('actioncomplete', this, action);
8368 // failure condition..
8369 // we have a scenario where updates need confirming.
8370 // eg. if a locking scenario exists..
8371 // we look for { errors : { needs_confirm : true }} in the response.
8373 (typeof(action.result) != 'undefined') &&
8374 (typeof(action.result.errors) != 'undefined') &&
8375 (typeof(action.result.errors.needs_confirm) != 'undefined')
8378 Roo.log("not supported yet");
8381 Roo.MessageBox.confirm(
8382 "Change requires confirmation",
8383 action.result.errorMsg,
8388 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8398 Roo.callback(o.failure, o.scope, [this, action]);
8399 // show an error message if no failed handler is set..
8400 if (!this.hasListener('actionfailed')) {
8401 Roo.log("need to add dialog support");
8403 Roo.MessageBox.alert("Error",
8404 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8405 action.result.errorMsg :
8406 "Saving Failed, please check your entries or try again"
8411 this.fireEvent('actionfailed', this, action);
8416 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8417 * @param {String} id The value to search for
8420 findField : function(id){
8421 var items = this.getItems();
8422 var field = items.get(id);
8424 items.each(function(f){
8425 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8432 return field || null;
8435 * Mark fields in this form invalid in bulk.
8436 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8437 * @return {BasicForm} this
8439 markInvalid : function(errors){
8440 if(errors instanceof Array){
8441 for(var i = 0, len = errors.length; i < len; i++){
8442 var fieldError = errors[i];
8443 var f = this.findField(fieldError.id);
8445 f.markInvalid(fieldError.msg);
8451 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8452 field.markInvalid(errors[id]);
8456 //Roo.each(this.childForms || [], function (f) {
8457 // f.markInvalid(errors);
8464 * Set values for fields in this form in bulk.
8465 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8466 * @return {BasicForm} this
8468 setValues : function(values){
8469 if(values instanceof Array){ // array of objects
8470 for(var i = 0, len = values.length; i < len; i++){
8472 var f = this.findField(v.id);
8474 f.setValue(v.value);
8475 if(this.trackResetOnLoad){
8476 f.originalValue = f.getValue();
8480 }else{ // object hash
8483 if(typeof values[id] != 'function' && (field = this.findField(id))){
8485 if (field.setFromData &&
8487 field.displayField &&
8488 // combos' with local stores can
8489 // be queried via setValue()
8490 // to set their value..
8491 (field.store && !field.store.isLocal)
8495 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8496 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8497 field.setFromData(sd);
8499 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8501 field.setFromData(values);
8504 field.setValue(values[id]);
8508 if(this.trackResetOnLoad){
8509 field.originalValue = field.getValue();
8515 //Roo.each(this.childForms || [], function (f) {
8516 // f.setValues(values);
8523 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8524 * they are returned as an array.
8525 * @param {Boolean} asString
8528 getValues : function(asString){
8529 //if (this.childForms) {
8530 // copy values from the child forms
8531 // Roo.each(this.childForms, function (f) {
8532 // this.setValues(f.getValues());
8538 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8539 if(asString === true){
8542 return Roo.urlDecode(fs);
8546 * Returns the fields in this form as an object with key/value pairs.
8547 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8550 getFieldValues : function(with_hidden)
8552 var items = this.getItems();
8554 items.each(function(f){
8560 var v = f.getValue();
8562 if (f.inputType =='radio') {
8563 if (typeof(ret[f.getName()]) == 'undefined') {
8564 ret[f.getName()] = ''; // empty..
8567 if (!f.el.dom.checked) {
8575 if(f.xtype == 'MoneyField'){
8576 ret[f.currencyName] = f.getCurrency();
8579 // not sure if this supported any more..
8580 if ((typeof(v) == 'object') && f.getRawValue) {
8581 v = f.getRawValue() ; // dates..
8583 // combo boxes where name != hiddenName...
8584 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8585 ret[f.name] = f.getRawValue();
8587 ret[f.getName()] = v;
8594 * Clears all invalid messages in this form.
8595 * @return {BasicForm} this
8597 clearInvalid : function(){
8598 var items = this.getItems();
8600 items.each(function(f){
8609 * @return {BasicForm} this
8612 var items = this.getItems();
8613 items.each(function(f){
8617 Roo.each(this.childForms || [], function (f) {
8625 getItems : function()
8627 var r=new Roo.util.MixedCollection(false, function(o){
8628 return o.id || (o.id = Roo.id());
8630 var iter = function(el) {
8637 Roo.each(el.items,function(e) {
8646 hideFields : function(items)
8648 Roo.each(items, function(i){
8650 var f = this.findField(i);
8661 showFields : function(items)
8663 Roo.each(items, function(i){
8665 var f = this.findField(i);
8678 Roo.apply(Roo.bootstrap.Form, {
8705 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8706 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8707 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8708 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8711 this.maskEl.top.enableDisplayMode("block");
8712 this.maskEl.left.enableDisplayMode("block");
8713 this.maskEl.bottom.enableDisplayMode("block");
8714 this.maskEl.right.enableDisplayMode("block");
8716 this.toolTip = new Roo.bootstrap.Tooltip({
8717 cls : 'roo-form-error-popover',
8719 'left' : ['r-l', [-2,0], 'right'],
8720 'right' : ['l-r', [2,0], 'left'],
8721 'bottom' : ['tl-bl', [0,2], 'top'],
8722 'top' : [ 'bl-tl', [0,-2], 'bottom']
8726 this.toolTip.render(Roo.get(document.body));
8728 this.toolTip.el.enableDisplayMode("block");
8730 Roo.get(document.body).on('click', function(){
8734 Roo.get(document.body).on('touchstart', function(){
8738 this.isApplied = true
8741 mask : function(form, target)
8745 this.target = target;
8747 if(!this.form.errorMask || !target.el){
8751 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8753 Roo.log(scrollable);
8755 var ot = this.target.el.calcOffsetsTo(scrollable);
8757 var scrollTo = ot[1] - this.form.maskOffset;
8759 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8761 scrollable.scrollTo('top', scrollTo);
8763 var box = this.target.el.getBox();
8765 var zIndex = Roo.bootstrap.Modal.zIndex++;
8768 this.maskEl.top.setStyle('position', 'absolute');
8769 this.maskEl.top.setStyle('z-index', zIndex);
8770 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8771 this.maskEl.top.setLeft(0);
8772 this.maskEl.top.setTop(0);
8773 this.maskEl.top.show();
8775 this.maskEl.left.setStyle('position', 'absolute');
8776 this.maskEl.left.setStyle('z-index', zIndex);
8777 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8778 this.maskEl.left.setLeft(0);
8779 this.maskEl.left.setTop(box.y - this.padding);
8780 this.maskEl.left.show();
8782 this.maskEl.bottom.setStyle('position', 'absolute');
8783 this.maskEl.bottom.setStyle('z-index', zIndex);
8784 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8785 this.maskEl.bottom.setLeft(0);
8786 this.maskEl.bottom.setTop(box.bottom + this.padding);
8787 this.maskEl.bottom.show();
8789 this.maskEl.right.setStyle('position', 'absolute');
8790 this.maskEl.right.setStyle('z-index', zIndex);
8791 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8792 this.maskEl.right.setLeft(box.right + this.padding);
8793 this.maskEl.right.setTop(box.y - this.padding);
8794 this.maskEl.right.show();
8796 this.toolTip.bindEl = this.target.el;
8798 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8800 var tip = this.target.blankText;
8802 if(this.target.getValue() !== '' ) {
8804 if (this.target.invalidText.length) {
8805 tip = this.target.invalidText;
8806 } else if (this.target.regexText.length){
8807 tip = this.target.regexText;
8811 this.toolTip.show(tip);
8813 this.intervalID = window.setInterval(function() {
8814 Roo.bootstrap.Form.popover.unmask();
8817 window.onwheel = function(){ return false;};
8819 (function(){ this.isMasked = true; }).defer(500, this);
8825 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8829 this.maskEl.top.setStyle('position', 'absolute');
8830 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8831 this.maskEl.top.hide();
8833 this.maskEl.left.setStyle('position', 'absolute');
8834 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8835 this.maskEl.left.hide();
8837 this.maskEl.bottom.setStyle('position', 'absolute');
8838 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8839 this.maskEl.bottom.hide();
8841 this.maskEl.right.setStyle('position', 'absolute');
8842 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8843 this.maskEl.right.hide();
8845 this.toolTip.hide();
8847 this.toolTip.el.hide();
8849 window.onwheel = function(){ return true;};
8851 if(this.intervalID){
8852 window.clearInterval(this.intervalID);
8853 this.intervalID = false;
8856 this.isMasked = false;
8866 * Ext JS Library 1.1.1
8867 * Copyright(c) 2006-2007, Ext JS, LLC.
8869 * Originally Released Under LGPL - original licence link has changed is not relivant.
8872 * <script type="text/javascript">
8875 * @class Roo.form.VTypes
8876 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8879 Roo.form.VTypes = function(){
8880 // closure these in so they are only created once.
8881 var alpha = /^[a-zA-Z_]+$/;
8882 var alphanum = /^[a-zA-Z0-9_]+$/;
8883 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8884 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8886 // All these messages and functions are configurable
8889 * The function used to validate email addresses
8890 * @param {String} value The email address
8892 'email' : function(v){
8893 return email.test(v);
8896 * The error text to display when the email validation function returns false
8899 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8901 * The keystroke filter mask to be applied on email input
8904 'emailMask' : /[a-z0-9_\.\-@]/i,
8907 * The function used to validate URLs
8908 * @param {String} value The URL
8910 'url' : function(v){
8914 * The error text to display when the url validation function returns false
8917 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8920 * The function used to validate alpha values
8921 * @param {String} value The value
8923 'alpha' : function(v){
8924 return alpha.test(v);
8927 * The error text to display when the alpha validation function returns false
8930 'alphaText' : 'This field should only contain letters and _',
8932 * The keystroke filter mask to be applied on alpha input
8935 'alphaMask' : /[a-z_]/i,
8938 * The function used to validate alphanumeric values
8939 * @param {String} value The value
8941 'alphanum' : function(v){
8942 return alphanum.test(v);
8945 * The error text to display when the alphanumeric validation function returns false
8948 'alphanumText' : 'This field should only contain letters, numbers and _',
8950 * The keystroke filter mask to be applied on alphanumeric input
8953 'alphanumMask' : /[a-z0-9_]/i
8963 * @class Roo.bootstrap.Input
8964 * @extends Roo.bootstrap.Component
8965 * Bootstrap Input class
8966 * @cfg {Boolean} disabled is it disabled
8967 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8968 * @cfg {String} name name of the input
8969 * @cfg {string} fieldLabel - the label associated
8970 * @cfg {string} placeholder - placeholder to put in text.
8971 * @cfg {string} before - input group add on before
8972 * @cfg {string} after - input group add on after
8973 * @cfg {string} size - (lg|sm) or leave empty..
8974 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8975 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8976 * @cfg {Number} md colspan out of 12 for computer-sized screens
8977 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8978 * @cfg {string} value default value of the input
8979 * @cfg {Number} labelWidth set the width of label
8980 * @cfg {Number} labellg set the width of label (1-12)
8981 * @cfg {Number} labelmd set the width of label (1-12)
8982 * @cfg {Number} labelsm set the width of label (1-12)
8983 * @cfg {Number} labelxs set the width of label (1-12)
8984 * @cfg {String} labelAlign (top|left)
8985 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8986 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8987 * @cfg {String} indicatorpos (left|right) default left
8988 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8989 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8991 * @cfg {String} align (left|center|right) Default left
8992 * @cfg {Boolean} forceFeedback (true|false) Default false
8995 * Create a new Input
8996 * @param {Object} config The config object
8999 Roo.bootstrap.Input = function(config){
9001 Roo.bootstrap.Input.superclass.constructor.call(this, config);
9006 * Fires when this field receives input focus.
9007 * @param {Roo.form.Field} this
9012 * Fires when this field loses input focus.
9013 * @param {Roo.form.Field} this
9018 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9019 * {@link Roo.EventObject#getKey} to determine which key was pressed.
9020 * @param {Roo.form.Field} this
9021 * @param {Roo.EventObject} e The event object
9026 * Fires just before the field blurs if the field value has changed.
9027 * @param {Roo.form.Field} this
9028 * @param {Mixed} newValue The new value
9029 * @param {Mixed} oldValue The original value
9034 * Fires after the field has been marked as invalid.
9035 * @param {Roo.form.Field} this
9036 * @param {String} msg The validation message
9041 * Fires after the field has been validated with no errors.
9042 * @param {Roo.form.Field} this
9047 * Fires after the key up
9048 * @param {Roo.form.Field} this
9049 * @param {Roo.EventObject} e The event Object
9055 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9057 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9058 automatic validation (defaults to "keyup").
9060 validationEvent : "keyup",
9062 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9064 validateOnBlur : true,
9066 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9068 validationDelay : 250,
9070 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9072 focusClass : "x-form-focus", // not needed???
9076 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9078 invalidClass : "has-warning",
9081 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9083 validClass : "has-success",
9086 * @cfg {Boolean} hasFeedback (true|false) default true
9091 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9093 invalidFeedbackClass : "glyphicon-warning-sign",
9096 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9098 validFeedbackClass : "glyphicon-ok",
9101 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9103 selectOnFocus : false,
9106 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9110 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9115 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9117 disableKeyFilter : false,
9120 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9124 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9128 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9130 blankText : "Please complete this mandatory field",
9133 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9137 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9139 maxLength : Number.MAX_VALUE,
9141 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9143 minLengthText : "The minimum length for this field is {0}",
9145 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9147 maxLengthText : "The maximum length for this field is {0}",
9151 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9152 * If available, this function will be called only after the basic validators all return true, and will be passed the
9153 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9157 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9158 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9159 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9163 * @cfg {String} regexText -- Depricated - use Invalid Text
9168 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9174 autocomplete: false,
9193 formatedValue : false,
9194 forceFeedback : false,
9196 indicatorpos : 'left',
9206 parentLabelAlign : function()
9209 while (parent.parent()) {
9210 parent = parent.parent();
9211 if (typeof(parent.labelAlign) !='undefined') {
9212 return parent.labelAlign;
9219 getAutoCreate : function()
9221 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9227 if(this.inputType != 'hidden'){
9228 cfg.cls = 'form-group' //input-group
9234 type : this.inputType,
9236 cls : 'form-control',
9237 placeholder : this.placeholder || '',
9238 autocomplete : this.autocomplete || 'new-password'
9241 if(this.capture.length){
9242 input.capture = this.capture;
9245 if(this.accept.length){
9246 input.accept = this.accept + "/*";
9250 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9253 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9254 input.maxLength = this.maxLength;
9257 if (this.disabled) {
9258 input.disabled=true;
9261 if (this.readOnly) {
9262 input.readonly=true;
9266 input.name = this.name;
9270 input.cls += ' input-' + this.size;
9274 ['xs','sm','md','lg'].map(function(size){
9275 if (settings[size]) {
9276 cfg.cls += ' col-' + size + '-' + settings[size];
9280 var inputblock = input;
9284 cls: 'glyphicon form-control-feedback'
9287 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9290 cls : 'has-feedback',
9298 if (this.before || this.after) {
9301 cls : 'input-group',
9305 if (this.before && typeof(this.before) == 'string') {
9307 inputblock.cn.push({
9309 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9313 if (this.before && typeof(this.before) == 'object') {
9314 this.before = Roo.factory(this.before);
9316 inputblock.cn.push({
9318 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9319 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9323 inputblock.cn.push(input);
9325 if (this.after && typeof(this.after) == 'string') {
9326 inputblock.cn.push({
9328 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9332 if (this.after && typeof(this.after) == 'object') {
9333 this.after = Roo.factory(this.after);
9335 inputblock.cn.push({
9337 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9338 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9342 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9343 inputblock.cls += ' has-feedback';
9344 inputblock.cn.push(feedback);
9349 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9350 tooltip : 'This field is required'
9352 if (Roo.bootstrap.version == 4) {
9355 style : 'display-none'
9358 if (align ==='left' && this.fieldLabel.length) {
9360 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9367 cls : 'control-label col-form-label',
9368 html : this.fieldLabel
9379 var labelCfg = cfg.cn[1];
9380 var contentCfg = cfg.cn[2];
9382 if(this.indicatorpos == 'right'){
9387 cls : 'control-label col-form-label',
9391 html : this.fieldLabel
9405 labelCfg = cfg.cn[0];
9406 contentCfg = cfg.cn[1];
9410 if(this.labelWidth > 12){
9411 labelCfg.style = "width: " + this.labelWidth + 'px';
9414 if(this.labelWidth < 13 && this.labelmd == 0){
9415 this.labelmd = this.labelWidth;
9418 if(this.labellg > 0){
9419 labelCfg.cls += ' col-lg-' + this.labellg;
9420 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9423 if(this.labelmd > 0){
9424 labelCfg.cls += ' col-md-' + this.labelmd;
9425 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9428 if(this.labelsm > 0){
9429 labelCfg.cls += ' col-sm-' + this.labelsm;
9430 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9433 if(this.labelxs > 0){
9434 labelCfg.cls += ' col-xs-' + this.labelxs;
9435 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9439 } else if ( this.fieldLabel.length) {
9444 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9445 tooltip : 'This field is required'
9449 //cls : 'input-group-addon',
9450 html : this.fieldLabel
9458 if(this.indicatorpos == 'right'){
9463 //cls : 'input-group-addon',
9464 html : this.fieldLabel
9469 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9470 tooltip : 'This field is required'
9490 if (this.parentType === 'Navbar' && this.parent().bar) {
9491 cfg.cls += ' navbar-form';
9494 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9495 // on BS4 we do this only if not form
9496 cfg.cls += ' navbar-form';
9504 * return the real input element.
9506 inputEl: function ()
9508 return this.el.select('input.form-control',true).first();
9511 tooltipEl : function()
9513 return this.inputEl();
9516 indicatorEl : function()
9518 if (Roo.bootstrap.version == 4) {
9519 return false; // not enabled in v4 yet.
9522 var indicator = this.el.select('i.roo-required-indicator',true).first();
9532 setDisabled : function(v)
9534 var i = this.inputEl().dom;
9536 i.removeAttribute('disabled');
9540 i.setAttribute('disabled','true');
9542 initEvents : function()
9545 this.inputEl().on("keydown" , this.fireKey, this);
9546 this.inputEl().on("focus", this.onFocus, this);
9547 this.inputEl().on("blur", this.onBlur, this);
9549 this.inputEl().relayEvent('keyup', this);
9551 this.indicator = this.indicatorEl();
9554 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9557 // reference to original value for reset
9558 this.originalValue = this.getValue();
9559 //Roo.form.TextField.superclass.initEvents.call(this);
9560 if(this.validationEvent == 'keyup'){
9561 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9562 this.inputEl().on('keyup', this.filterValidation, this);
9564 else if(this.validationEvent !== false){
9565 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9568 if(this.selectOnFocus){
9569 this.on("focus", this.preFocus, this);
9572 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9573 this.inputEl().on("keypress", this.filterKeys, this);
9575 this.inputEl().relayEvent('keypress', this);
9578 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9579 this.el.on("click", this.autoSize, this);
9582 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9583 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9586 if (typeof(this.before) == 'object') {
9587 this.before.render(this.el.select('.roo-input-before',true).first());
9589 if (typeof(this.after) == 'object') {
9590 this.after.render(this.el.select('.roo-input-after',true).first());
9593 this.inputEl().on('change', this.onChange, this);
9596 filterValidation : function(e){
9597 if(!e.isNavKeyPress()){
9598 this.validationTask.delay(this.validationDelay);
9602 * Validates the field value
9603 * @return {Boolean} True if the value is valid, else false
9605 validate : function(){
9606 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9607 if(this.disabled || this.validateValue(this.getRawValue())){
9618 * Validates a value according to the field's validation rules and marks the field as invalid
9619 * if the validation fails
9620 * @param {Mixed} value The value to validate
9621 * @return {Boolean} True if the value is valid, else false
9623 validateValue : function(value)
9625 if(this.getVisibilityEl().hasClass('hidden')){
9629 if(value.length < 1) { // if it's blank
9630 if(this.allowBlank){
9636 if(value.length < this.minLength){
9639 if(value.length > this.maxLength){
9643 var vt = Roo.form.VTypes;
9644 if(!vt[this.vtype](value, this)){
9648 if(typeof this.validator == "function"){
9649 var msg = this.validator(value);
9653 if (typeof(msg) == 'string') {
9654 this.invalidText = msg;
9658 if(this.regex && !this.regex.test(value)){
9666 fireKey : function(e){
9667 //Roo.log('field ' + e.getKey());
9668 if(e.isNavKeyPress()){
9669 this.fireEvent("specialkey", this, e);
9672 focus : function (selectText){
9674 this.inputEl().focus();
9675 if(selectText === true){
9676 this.inputEl().dom.select();
9682 onFocus : function(){
9683 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9684 // this.el.addClass(this.focusClass);
9687 this.hasFocus = true;
9688 this.startValue = this.getValue();
9689 this.fireEvent("focus", this);
9693 beforeBlur : Roo.emptyFn,
9697 onBlur : function(){
9699 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9700 //this.el.removeClass(this.focusClass);
9702 this.hasFocus = false;
9703 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9706 var v = this.getValue();
9707 if(String(v) !== String(this.startValue)){
9708 this.fireEvent('change', this, v, this.startValue);
9710 this.fireEvent("blur", this);
9713 onChange : function(e)
9715 var v = this.getValue();
9716 if(String(v) !== String(this.startValue)){
9717 this.fireEvent('change', this, v, this.startValue);
9723 * Resets the current field value to the originally loaded value and clears any validation messages
9726 this.setValue(this.originalValue);
9730 * Returns the name of the field
9731 * @return {Mixed} name The name field
9733 getName: function(){
9737 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9738 * @return {Mixed} value The field value
9740 getValue : function(){
9742 var v = this.inputEl().getValue();
9747 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9748 * @return {Mixed} value The field value
9750 getRawValue : function(){
9751 var v = this.inputEl().getValue();
9757 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9758 * @param {Mixed} value The value to set
9760 setRawValue : function(v){
9761 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9764 selectText : function(start, end){
9765 var v = this.getRawValue();
9767 start = start === undefined ? 0 : start;
9768 end = end === undefined ? v.length : end;
9769 var d = this.inputEl().dom;
9770 if(d.setSelectionRange){
9771 d.setSelectionRange(start, end);
9772 }else if(d.createTextRange){
9773 var range = d.createTextRange();
9774 range.moveStart("character", start);
9775 range.moveEnd("character", v.length-end);
9782 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9783 * @param {Mixed} value The value to set
9785 setValue : function(v){
9788 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9794 processValue : function(value){
9795 if(this.stripCharsRe){
9796 var newValue = value.replace(this.stripCharsRe, '');
9797 if(newValue !== value){
9798 this.setRawValue(newValue);
9805 preFocus : function(){
9807 if(this.selectOnFocus){
9808 this.inputEl().dom.select();
9811 filterKeys : function(e){
9813 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9816 var c = e.getCharCode(), cc = String.fromCharCode(c);
9817 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9820 if(!this.maskRe.test(cc)){
9825 * Clear any invalid styles/messages for this field
9827 clearInvalid : function(){
9829 if(!this.el || this.preventMark){ // not rendered
9834 this.el.removeClass([this.invalidClass, 'is-invalid']);
9836 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9838 var feedback = this.el.select('.form-control-feedback', true).first();
9841 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9847 this.indicator.removeClass('visible');
9848 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9851 this.fireEvent('valid', this);
9855 * Mark this field as valid
9857 markValid : function()
9859 if(!this.el || this.preventMark){ // not rendered...
9863 this.el.removeClass([this.invalidClass, this.validClass]);
9864 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9866 var feedback = this.el.select('.form-control-feedback', true).first();
9869 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9873 this.indicator.removeClass('visible');
9874 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9881 if(this.allowBlank && !this.getRawValue().length){
9884 if (Roo.bootstrap.version == 3) {
9885 this.el.addClass(this.validClass);
9887 this.inputEl().addClass('is-valid');
9890 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9892 var feedback = this.el.select('.form-control-feedback', true).first();
9895 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9896 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9901 this.fireEvent('valid', this);
9905 * Mark this field as invalid
9906 * @param {String} msg The validation message
9908 markInvalid : function(msg)
9910 if(!this.el || this.preventMark){ // not rendered
9914 this.el.removeClass([this.invalidClass, this.validClass]);
9915 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9917 var feedback = this.el.select('.form-control-feedback', true).first();
9920 this.el.select('.form-control-feedback', true).first().removeClass(
9921 [this.invalidFeedbackClass, this.validFeedbackClass]);
9928 if(this.allowBlank && !this.getRawValue().length){
9933 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9934 this.indicator.addClass('visible');
9936 if (Roo.bootstrap.version == 3) {
9937 this.el.addClass(this.invalidClass);
9939 this.inputEl().addClass('is-invalid');
9944 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9946 var feedback = this.el.select('.form-control-feedback', true).first();
9949 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9951 if(this.getValue().length || this.forceFeedback){
9952 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9959 this.fireEvent('invalid', this, msg);
9962 SafariOnKeyDown : function(event)
9964 // this is a workaround for a password hang bug on chrome/ webkit.
9965 if (this.inputEl().dom.type != 'password') {
9969 var isSelectAll = false;
9971 if(this.inputEl().dom.selectionEnd > 0){
9972 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9974 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9975 event.preventDefault();
9980 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9982 event.preventDefault();
9983 // this is very hacky as keydown always get's upper case.
9985 var cc = String.fromCharCode(event.getCharCode());
9986 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9990 adjustWidth : function(tag, w){
9991 tag = tag.toLowerCase();
9992 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9993 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9997 if(tag == 'textarea'){
10000 }else if(Roo.isOpera){
10001 if(tag == 'input'){
10004 if(tag == 'textarea'){
10012 setFieldLabel : function(v)
10014 if(!this.rendered){
10018 if(this.indicatorEl()){
10019 var ar = this.el.select('label > span',true);
10021 if (ar.elements.length) {
10022 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10023 this.fieldLabel = v;
10027 var br = this.el.select('label',true);
10029 if(br.elements.length) {
10030 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10031 this.fieldLabel = v;
10035 Roo.log('Cannot Found any of label > span || label in input');
10039 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10040 this.fieldLabel = v;
10055 * @class Roo.bootstrap.TextArea
10056 * @extends Roo.bootstrap.Input
10057 * Bootstrap TextArea class
10058 * @cfg {Number} cols Specifies the visible width of a text area
10059 * @cfg {Number} rows Specifies the visible number of lines in a text area
10060 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10061 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10062 * @cfg {string} html text
10065 * Create a new TextArea
10066 * @param {Object} config The config object
10069 Roo.bootstrap.TextArea = function(config){
10070 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10074 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10084 getAutoCreate : function(){
10086 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10092 if(this.inputType != 'hidden'){
10093 cfg.cls = 'form-group' //input-group
10101 value : this.value || '',
10102 html: this.html || '',
10103 cls : 'form-control',
10104 placeholder : this.placeholder || ''
10108 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10109 input.maxLength = this.maxLength;
10113 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10117 input.cols = this.cols;
10120 if (this.readOnly) {
10121 input.readonly = true;
10125 input.name = this.name;
10129 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10133 ['xs','sm','md','lg'].map(function(size){
10134 if (settings[size]) {
10135 cfg.cls += ' col-' + size + '-' + settings[size];
10139 var inputblock = input;
10141 if(this.hasFeedback && !this.allowBlank){
10145 cls: 'glyphicon form-control-feedback'
10149 cls : 'has-feedback',
10158 if (this.before || this.after) {
10161 cls : 'input-group',
10165 inputblock.cn.push({
10167 cls : 'input-group-addon',
10172 inputblock.cn.push(input);
10174 if(this.hasFeedback && !this.allowBlank){
10175 inputblock.cls += ' has-feedback';
10176 inputblock.cn.push(feedback);
10180 inputblock.cn.push({
10182 cls : 'input-group-addon',
10189 if (align ==='left' && this.fieldLabel.length) {
10194 cls : 'control-label',
10195 html : this.fieldLabel
10206 if(this.labelWidth > 12){
10207 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10210 if(this.labelWidth < 13 && this.labelmd == 0){
10211 this.labelmd = this.labelWidth;
10214 if(this.labellg > 0){
10215 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10216 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10219 if(this.labelmd > 0){
10220 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10221 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10224 if(this.labelsm > 0){
10225 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10226 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10229 if(this.labelxs > 0){
10230 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10231 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10234 } else if ( this.fieldLabel.length) {
10239 //cls : 'input-group-addon',
10240 html : this.fieldLabel
10258 if (this.disabled) {
10259 input.disabled=true;
10266 * return the real textarea element.
10268 inputEl: function ()
10270 return this.el.select('textarea.form-control',true).first();
10274 * Clear any invalid styles/messages for this field
10276 clearInvalid : function()
10279 if(!this.el || this.preventMark){ // not rendered
10283 var label = this.el.select('label', true).first();
10284 var icon = this.el.select('i.fa-star', true).first();
10289 this.el.removeClass( this.validClass);
10290 this.inputEl().removeClass('is-invalid');
10292 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10294 var feedback = this.el.select('.form-control-feedback', true).first();
10297 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10302 this.fireEvent('valid', this);
10306 * Mark this field as valid
10308 markValid : function()
10310 if(!this.el || this.preventMark){ // not rendered
10314 this.el.removeClass([this.invalidClass, this.validClass]);
10315 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10317 var feedback = this.el.select('.form-control-feedback', true).first();
10320 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10323 if(this.disabled || this.allowBlank){
10327 var label = this.el.select('label', true).first();
10328 var icon = this.el.select('i.fa-star', true).first();
10333 if (Roo.bootstrap.version == 3) {
10334 this.el.addClass(this.validClass);
10336 this.inputEl().addClass('is-valid');
10340 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10342 var feedback = this.el.select('.form-control-feedback', true).first();
10345 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10346 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10351 this.fireEvent('valid', this);
10355 * Mark this field as invalid
10356 * @param {String} msg The validation message
10358 markInvalid : function(msg)
10360 if(!this.el || this.preventMark){ // not rendered
10364 this.el.removeClass([this.invalidClass, this.validClass]);
10365 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10367 var feedback = this.el.select('.form-control-feedback', true).first();
10370 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10373 if(this.disabled || this.allowBlank){
10377 var label = this.el.select('label', true).first();
10378 var icon = this.el.select('i.fa-star', true).first();
10380 if(!this.getValue().length && label && !icon){
10381 this.el.createChild({
10383 cls : 'text-danger fa fa-lg fa-star',
10384 tooltip : 'This field is required',
10385 style : 'margin-right:5px;'
10389 if (Roo.bootstrap.version == 3) {
10390 this.el.addClass(this.invalidClass);
10392 this.inputEl().addClass('is-invalid');
10395 // fixme ... this may be depricated need to test..
10396 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10398 var feedback = this.el.select('.form-control-feedback', true).first();
10401 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10403 if(this.getValue().length || this.forceFeedback){
10404 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10411 this.fireEvent('invalid', this, msg);
10419 * trigger field - base class for combo..
10424 * @class Roo.bootstrap.TriggerField
10425 * @extends Roo.bootstrap.Input
10426 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10427 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10428 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10429 * for which you can provide a custom implementation. For example:
10431 var trigger = new Roo.bootstrap.TriggerField();
10432 trigger.onTriggerClick = myTriggerFn;
10433 trigger.applyTo('my-field');
10436 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10437 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10438 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10439 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10440 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10443 * Create a new TriggerField.
10444 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10445 * to the base TextField)
10447 Roo.bootstrap.TriggerField = function(config){
10448 this.mimicing = false;
10449 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10452 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10454 * @cfg {String} triggerClass A CSS class to apply to the trigger
10457 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10462 * @cfg {Boolean} removable (true|false) special filter default false
10466 /** @cfg {Boolean} grow @hide */
10467 /** @cfg {Number} growMin @hide */
10468 /** @cfg {Number} growMax @hide */
10474 autoSize: Roo.emptyFn,
10478 deferHeight : true,
10481 actionMode : 'wrap',
10486 getAutoCreate : function(){
10488 var align = this.labelAlign || this.parentLabelAlign();
10493 cls: 'form-group' //input-group
10500 type : this.inputType,
10501 cls : 'form-control',
10502 autocomplete: 'new-password',
10503 placeholder : this.placeholder || ''
10507 input.name = this.name;
10510 input.cls += ' input-' + this.size;
10513 if (this.disabled) {
10514 input.disabled=true;
10517 var inputblock = input;
10519 if(this.hasFeedback && !this.allowBlank){
10523 cls: 'glyphicon form-control-feedback'
10526 if(this.removable && !this.editable && !this.tickable){
10528 cls : 'has-feedback',
10534 cls : 'roo-combo-removable-btn close'
10541 cls : 'has-feedback',
10550 if(this.removable && !this.editable && !this.tickable){
10552 cls : 'roo-removable',
10558 cls : 'roo-combo-removable-btn close'
10565 if (this.before || this.after) {
10568 cls : 'input-group',
10572 inputblock.cn.push({
10574 cls : 'input-group-addon input-group-prepend input-group-text',
10579 inputblock.cn.push(input);
10581 if(this.hasFeedback && !this.allowBlank){
10582 inputblock.cls += ' has-feedback';
10583 inputblock.cn.push(feedback);
10587 inputblock.cn.push({
10589 cls : 'input-group-addon input-group-append input-group-text',
10598 var ibwrap = inputblock;
10603 cls: 'roo-select2-choices',
10607 cls: 'roo-select2-search-field',
10619 cls: 'roo-select2-container input-group',
10624 cls: 'form-hidden-field'
10630 if(!this.multiple && this.showToggleBtn){
10636 if (this.caret != false) {
10639 cls: 'fa fa-' + this.caret
10646 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10651 cls: 'combobox-clear',
10665 combobox.cls += ' roo-select2-container-multi';
10669 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10670 tooltip : 'This field is required'
10672 if (Roo.bootstrap.version == 4) {
10675 style : 'display:none'
10680 if (align ==='left' && this.fieldLabel.length) {
10682 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10689 cls : 'control-label',
10690 html : this.fieldLabel
10702 var labelCfg = cfg.cn[1];
10703 var contentCfg = cfg.cn[2];
10705 if(this.indicatorpos == 'right'){
10710 cls : 'control-label',
10714 html : this.fieldLabel
10728 labelCfg = cfg.cn[0];
10729 contentCfg = cfg.cn[1];
10732 if(this.labelWidth > 12){
10733 labelCfg.style = "width: " + this.labelWidth + 'px';
10736 if(this.labelWidth < 13 && this.labelmd == 0){
10737 this.labelmd = this.labelWidth;
10740 if(this.labellg > 0){
10741 labelCfg.cls += ' col-lg-' + this.labellg;
10742 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10745 if(this.labelmd > 0){
10746 labelCfg.cls += ' col-md-' + this.labelmd;
10747 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10750 if(this.labelsm > 0){
10751 labelCfg.cls += ' col-sm-' + this.labelsm;
10752 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10755 if(this.labelxs > 0){
10756 labelCfg.cls += ' col-xs-' + this.labelxs;
10757 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10760 } else if ( this.fieldLabel.length) {
10761 // Roo.log(" label");
10766 //cls : 'input-group-addon',
10767 html : this.fieldLabel
10775 if(this.indicatorpos == 'right'){
10783 html : this.fieldLabel
10797 // Roo.log(" no label && no align");
10804 ['xs','sm','md','lg'].map(function(size){
10805 if (settings[size]) {
10806 cfg.cls += ' col-' + size + '-' + settings[size];
10817 onResize : function(w, h){
10818 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10819 // if(typeof w == 'number'){
10820 // var x = w - this.trigger.getWidth();
10821 // this.inputEl().setWidth(this.adjustWidth('input', x));
10822 // this.trigger.setStyle('left', x+'px');
10827 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10830 getResizeEl : function(){
10831 return this.inputEl();
10835 getPositionEl : function(){
10836 return this.inputEl();
10840 alignErrorIcon : function(){
10841 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10845 initEvents : function(){
10849 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10850 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10851 if(!this.multiple && this.showToggleBtn){
10852 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10853 if(this.hideTrigger){
10854 this.trigger.setDisplayed(false);
10856 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10860 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10863 if(this.removable && !this.editable && !this.tickable){
10864 var close = this.closeTriggerEl();
10867 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10868 close.on('click', this.removeBtnClick, this, close);
10872 //this.trigger.addClassOnOver('x-form-trigger-over');
10873 //this.trigger.addClassOnClick('x-form-trigger-click');
10876 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10880 closeTriggerEl : function()
10882 var close = this.el.select('.roo-combo-removable-btn', true).first();
10883 return close ? close : false;
10886 removeBtnClick : function(e, h, el)
10888 e.preventDefault();
10890 if(this.fireEvent("remove", this) !== false){
10892 this.fireEvent("afterremove", this)
10896 createList : function()
10898 this.list = Roo.get(document.body).createChild({
10899 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10900 cls: 'typeahead typeahead-long dropdown-menu',
10901 style: 'display:none'
10904 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10909 initTrigger : function(){
10914 onDestroy : function(){
10916 this.trigger.removeAllListeners();
10917 // this.trigger.remove();
10920 // this.wrap.remove();
10922 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10926 onFocus : function(){
10927 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10929 if(!this.mimicing){
10930 this.wrap.addClass('x-trigger-wrap-focus');
10931 this.mimicing = true;
10932 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10933 if(this.monitorTab){
10934 this.el.on("keydown", this.checkTab, this);
10941 checkTab : function(e){
10942 if(e.getKey() == e.TAB){
10943 this.triggerBlur();
10948 onBlur : function(){
10953 mimicBlur : function(e, t){
10955 if(!this.wrap.contains(t) && this.validateBlur()){
10956 this.triggerBlur();
10962 triggerBlur : function(){
10963 this.mimicing = false;
10964 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10965 if(this.monitorTab){
10966 this.el.un("keydown", this.checkTab, this);
10968 //this.wrap.removeClass('x-trigger-wrap-focus');
10969 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10973 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10974 validateBlur : function(e, t){
10979 onDisable : function(){
10980 this.inputEl().dom.disabled = true;
10981 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10983 // this.wrap.addClass('x-item-disabled');
10988 onEnable : function(){
10989 this.inputEl().dom.disabled = false;
10990 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10992 // this.el.removeClass('x-item-disabled');
10997 onShow : function(){
10998 var ae = this.getActionEl();
11001 ae.dom.style.display = '';
11002 ae.dom.style.visibility = 'visible';
11008 onHide : function(){
11009 var ae = this.getActionEl();
11010 ae.dom.style.display = 'none';
11014 * The function that should handle the trigger's click event. This method does nothing by default until overridden
11015 * by an implementing function.
11017 * @param {EventObject} e
11019 onTriggerClick : Roo.emptyFn
11023 * Ext JS Library 1.1.1
11024 * Copyright(c) 2006-2007, Ext JS, LLC.
11026 * Originally Released Under LGPL - original licence link has changed is not relivant.
11029 * <script type="text/javascript">
11034 * @class Roo.data.SortTypes
11036 * Defines the default sorting (casting?) comparison functions used when sorting data.
11038 Roo.data.SortTypes = {
11040 * Default sort that does nothing
11041 * @param {Mixed} s The value being converted
11042 * @return {Mixed} The comparison value
11044 none : function(s){
11049 * The regular expression used to strip tags
11053 stripTagsRE : /<\/?[^>]+>/gi,
11056 * Strips all HTML tags to sort on text only
11057 * @param {Mixed} s The value being converted
11058 * @return {String} The comparison value
11060 asText : function(s){
11061 return String(s).replace(this.stripTagsRE, "");
11065 * Strips all HTML tags to sort on text only - Case insensitive
11066 * @param {Mixed} s The value being converted
11067 * @return {String} The comparison value
11069 asUCText : function(s){
11070 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11074 * Case insensitive string
11075 * @param {Mixed} s The value being converted
11076 * @return {String} The comparison value
11078 asUCString : function(s) {
11079 return String(s).toUpperCase();
11084 * @param {Mixed} s The value being converted
11085 * @return {Number} The comparison value
11087 asDate : function(s) {
11091 if(s instanceof Date){
11092 return s.getTime();
11094 return Date.parse(String(s));
11099 * @param {Mixed} s The value being converted
11100 * @return {Float} The comparison value
11102 asFloat : function(s) {
11103 var val = parseFloat(String(s).replace(/,/g, ""));
11112 * @param {Mixed} s The value being converted
11113 * @return {Number} The comparison value
11115 asInt : function(s) {
11116 var val = parseInt(String(s).replace(/,/g, ""));
11124 * Ext JS Library 1.1.1
11125 * Copyright(c) 2006-2007, Ext JS, LLC.
11127 * Originally Released Under LGPL - original licence link has changed is not relivant.
11130 * <script type="text/javascript">
11134 * @class Roo.data.Record
11135 * Instances of this class encapsulate both record <em>definition</em> information, and record
11136 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11137 * to access Records cached in an {@link Roo.data.Store} object.<br>
11139 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11140 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11143 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11145 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11146 * {@link #create}. The parameters are the same.
11147 * @param {Array} data An associative Array of data values keyed by the field name.
11148 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11149 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11150 * not specified an integer id is generated.
11152 Roo.data.Record = function(data, id){
11153 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11158 * Generate a constructor for a specific record layout.
11159 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11160 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11161 * Each field definition object may contain the following properties: <ul>
11162 * <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,
11163 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11164 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11165 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11166 * is being used, then this is a string containing the javascript expression to reference the data relative to
11167 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11168 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11169 * this may be omitted.</p></li>
11170 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11171 * <ul><li>auto (Default, implies no conversion)</li>
11176 * <li>date</li></ul></p></li>
11177 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11178 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11179 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11180 * by the Reader into an object that will be stored in the Record. It is passed the
11181 * following parameters:<ul>
11182 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11184 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11186 * <br>usage:<br><pre><code>
11187 var TopicRecord = Roo.data.Record.create(
11188 {name: 'title', mapping: 'topic_title'},
11189 {name: 'author', mapping: 'username'},
11190 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11191 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11192 {name: 'lastPoster', mapping: 'user2'},
11193 {name: 'excerpt', mapping: 'post_text'}
11196 var myNewRecord = new TopicRecord({
11197 title: 'Do my job please',
11200 lastPost: new Date(),
11201 lastPoster: 'Animal',
11202 excerpt: 'No way dude!'
11204 myStore.add(myNewRecord);
11209 Roo.data.Record.create = function(o){
11210 var f = function(){
11211 f.superclass.constructor.apply(this, arguments);
11213 Roo.extend(f, Roo.data.Record);
11214 var p = f.prototype;
11215 p.fields = new Roo.util.MixedCollection(false, function(field){
11218 for(var i = 0, len = o.length; i < len; i++){
11219 p.fields.add(new Roo.data.Field(o[i]));
11221 f.getField = function(name){
11222 return p.fields.get(name);
11227 Roo.data.Record.AUTO_ID = 1000;
11228 Roo.data.Record.EDIT = 'edit';
11229 Roo.data.Record.REJECT = 'reject';
11230 Roo.data.Record.COMMIT = 'commit';
11232 Roo.data.Record.prototype = {
11234 * Readonly flag - true if this record has been modified.
11243 join : function(store){
11244 this.store = store;
11248 * Set the named field to the specified value.
11249 * @param {String} name The name of the field to set.
11250 * @param {Object} value The value to set the field to.
11252 set : function(name, value){
11253 if(this.data[name] == value){
11257 if(!this.modified){
11258 this.modified = {};
11260 if(typeof this.modified[name] == 'undefined'){
11261 this.modified[name] = this.data[name];
11263 this.data[name] = value;
11264 if(!this.editing && this.store){
11265 this.store.afterEdit(this);
11270 * Get the value of the named field.
11271 * @param {String} name The name of the field to get the value of.
11272 * @return {Object} The value of the field.
11274 get : function(name){
11275 return this.data[name];
11279 beginEdit : function(){
11280 this.editing = true;
11281 this.modified = {};
11285 cancelEdit : function(){
11286 this.editing = false;
11287 delete this.modified;
11291 endEdit : function(){
11292 this.editing = false;
11293 if(this.dirty && this.store){
11294 this.store.afterEdit(this);
11299 * Usually called by the {@link Roo.data.Store} which owns the Record.
11300 * Rejects all changes made to the Record since either creation, or the last commit operation.
11301 * Modified fields are reverted to their original values.
11303 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11304 * of reject operations.
11306 reject : function(){
11307 var m = this.modified;
11309 if(typeof m[n] != "function"){
11310 this.data[n] = m[n];
11313 this.dirty = false;
11314 delete this.modified;
11315 this.editing = false;
11317 this.store.afterReject(this);
11322 * Usually called by the {@link Roo.data.Store} which owns the Record.
11323 * Commits all changes made to the Record since either creation, or the last commit operation.
11325 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11326 * of commit operations.
11328 commit : function(){
11329 this.dirty = false;
11330 delete this.modified;
11331 this.editing = false;
11333 this.store.afterCommit(this);
11338 hasError : function(){
11339 return this.error != null;
11343 clearError : function(){
11348 * Creates a copy of this record.
11349 * @param {String} id (optional) A new record id if you don't want to use this record's id
11352 copy : function(newId) {
11353 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11357 * Ext JS Library 1.1.1
11358 * Copyright(c) 2006-2007, Ext JS, LLC.
11360 * Originally Released Under LGPL - original licence link has changed is not relivant.
11363 * <script type="text/javascript">
11369 * @class Roo.data.Store
11370 * @extends Roo.util.Observable
11371 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11372 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11374 * 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
11375 * has no knowledge of the format of the data returned by the Proxy.<br>
11377 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11378 * instances from the data object. These records are cached and made available through accessor functions.
11380 * Creates a new Store.
11381 * @param {Object} config A config object containing the objects needed for the Store to access data,
11382 * and read the data into Records.
11384 Roo.data.Store = function(config){
11385 this.data = new Roo.util.MixedCollection(false);
11386 this.data.getKey = function(o){
11389 this.baseParams = {};
11391 this.paramNames = {
11396 "multisort" : "_multisort"
11399 if(config && config.data){
11400 this.inlineData = config.data;
11401 delete config.data;
11404 Roo.apply(this, config);
11406 if(this.reader){ // reader passed
11407 this.reader = Roo.factory(this.reader, Roo.data);
11408 this.reader.xmodule = this.xmodule || false;
11409 if(!this.recordType){
11410 this.recordType = this.reader.recordType;
11412 if(this.reader.onMetaChange){
11413 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11417 if(this.recordType){
11418 this.fields = this.recordType.prototype.fields;
11420 this.modified = [];
11424 * @event datachanged
11425 * Fires when the data cache has changed, and a widget which is using this Store
11426 * as a Record cache should refresh its view.
11427 * @param {Store} this
11429 datachanged : true,
11431 * @event metachange
11432 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11433 * @param {Store} this
11434 * @param {Object} meta The JSON metadata
11439 * Fires when Records have been added to the Store
11440 * @param {Store} this
11441 * @param {Roo.data.Record[]} records The array of Records added
11442 * @param {Number} index The index at which the record(s) were added
11447 * Fires when a Record has been removed from the Store
11448 * @param {Store} this
11449 * @param {Roo.data.Record} record The Record that was removed
11450 * @param {Number} index The index at which the record was removed
11455 * Fires when a Record has been updated
11456 * @param {Store} this
11457 * @param {Roo.data.Record} record The Record that was updated
11458 * @param {String} operation The update operation being performed. Value may be one of:
11460 Roo.data.Record.EDIT
11461 Roo.data.Record.REJECT
11462 Roo.data.Record.COMMIT
11468 * Fires when the data cache has been cleared.
11469 * @param {Store} this
11473 * @event beforeload
11474 * Fires before a request is made for a new data object. If the beforeload handler returns false
11475 * the load action will be canceled.
11476 * @param {Store} this
11477 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11481 * @event beforeloadadd
11482 * Fires after a new set of Records has been loaded.
11483 * @param {Store} this
11484 * @param {Roo.data.Record[]} records The Records that were loaded
11485 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11487 beforeloadadd : true,
11490 * Fires after a new set of Records has been loaded, before they are added to the store.
11491 * @param {Store} this
11492 * @param {Roo.data.Record[]} records The Records that were loaded
11493 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11494 * @params {Object} return from reader
11498 * @event loadexception
11499 * Fires if an exception occurs in the Proxy during loading.
11500 * Called with the signature of the Proxy's "loadexception" event.
11501 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11504 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11505 * @param {Object} load options
11506 * @param {Object} jsonData from your request (normally this contains the Exception)
11508 loadexception : true
11512 this.proxy = Roo.factory(this.proxy, Roo.data);
11513 this.proxy.xmodule = this.xmodule || false;
11514 this.relayEvents(this.proxy, ["loadexception"]);
11516 this.sortToggle = {};
11517 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11519 Roo.data.Store.superclass.constructor.call(this);
11521 if(this.inlineData){
11522 this.loadData(this.inlineData);
11523 delete this.inlineData;
11527 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11529 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11530 * without a remote query - used by combo/forms at present.
11534 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11537 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11540 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11541 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11544 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11545 * on any HTTP request
11548 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11551 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11555 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11556 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11558 remoteSort : false,
11561 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11562 * loaded or when a record is removed. (defaults to false).
11564 pruneModifiedRecords : false,
11567 lastOptions : null,
11570 * Add Records to the Store and fires the add event.
11571 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11573 add : function(records){
11574 records = [].concat(records);
11575 for(var i = 0, len = records.length; i < len; i++){
11576 records[i].join(this);
11578 var index = this.data.length;
11579 this.data.addAll(records);
11580 this.fireEvent("add", this, records, index);
11584 * Remove a Record from the Store and fires the remove event.
11585 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11587 remove : function(record){
11588 var index = this.data.indexOf(record);
11589 this.data.removeAt(index);
11591 if(this.pruneModifiedRecords){
11592 this.modified.remove(record);
11594 this.fireEvent("remove", this, record, index);
11598 * Remove all Records from the Store and fires the clear event.
11600 removeAll : function(){
11602 if(this.pruneModifiedRecords){
11603 this.modified = [];
11605 this.fireEvent("clear", this);
11609 * Inserts Records to the Store at the given index and fires the add event.
11610 * @param {Number} index The start index at which to insert the passed Records.
11611 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11613 insert : function(index, records){
11614 records = [].concat(records);
11615 for(var i = 0, len = records.length; i < len; i++){
11616 this.data.insert(index, records[i]);
11617 records[i].join(this);
11619 this.fireEvent("add", this, records, index);
11623 * Get the index within the cache of the passed Record.
11624 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11625 * @return {Number} The index of the passed Record. Returns -1 if not found.
11627 indexOf : function(record){
11628 return this.data.indexOf(record);
11632 * Get the index within the cache of the Record with the passed id.
11633 * @param {String} id The id of the Record to find.
11634 * @return {Number} The index of the Record. Returns -1 if not found.
11636 indexOfId : function(id){
11637 return this.data.indexOfKey(id);
11641 * Get the Record with the specified id.
11642 * @param {String} id The id of the Record to find.
11643 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11645 getById : function(id){
11646 return this.data.key(id);
11650 * Get the Record at the specified index.
11651 * @param {Number} index The index of the Record to find.
11652 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11654 getAt : function(index){
11655 return this.data.itemAt(index);
11659 * Returns a range of Records between specified indices.
11660 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11661 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11662 * @return {Roo.data.Record[]} An array of Records
11664 getRange : function(start, end){
11665 return this.data.getRange(start, end);
11669 storeOptions : function(o){
11670 o = Roo.apply({}, o);
11673 this.lastOptions = o;
11677 * Loads the Record cache from the configured Proxy using the configured Reader.
11679 * If using remote paging, then the first load call must specify the <em>start</em>
11680 * and <em>limit</em> properties in the options.params property to establish the initial
11681 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11683 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11684 * and this call will return before the new data has been loaded. Perform any post-processing
11685 * in a callback function, or in a "load" event handler.</strong>
11687 * @param {Object} options An object containing properties which control loading options:<ul>
11688 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11689 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11690 * passed the following arguments:<ul>
11691 * <li>r : Roo.data.Record[]</li>
11692 * <li>options: Options object from the load call</li>
11693 * <li>success: Boolean success indicator</li></ul></li>
11694 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11695 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11698 load : function(options){
11699 options = options || {};
11700 if(this.fireEvent("beforeload", this, options) !== false){
11701 this.storeOptions(options);
11702 var p = Roo.apply(options.params || {}, this.baseParams);
11703 // if meta was not loaded from remote source.. try requesting it.
11704 if (!this.reader.metaFromRemote) {
11705 p._requestMeta = 1;
11707 if(this.sortInfo && this.remoteSort){
11708 var pn = this.paramNames;
11709 p[pn["sort"]] = this.sortInfo.field;
11710 p[pn["dir"]] = this.sortInfo.direction;
11712 if (this.multiSort) {
11713 var pn = this.paramNames;
11714 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11717 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11722 * Reloads the Record cache from the configured Proxy using the configured Reader and
11723 * the options from the last load operation performed.
11724 * @param {Object} options (optional) An object containing properties which may override the options
11725 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11726 * the most recently used options are reused).
11728 reload : function(options){
11729 this.load(Roo.applyIf(options||{}, this.lastOptions));
11733 // Called as a callback by the Reader during a load operation.
11734 loadRecords : function(o, options, success){
11735 if(!o || success === false){
11736 if(success !== false){
11737 this.fireEvent("load", this, [], options, o);
11739 if(options.callback){
11740 options.callback.call(options.scope || this, [], options, false);
11744 // if data returned failure - throw an exception.
11745 if (o.success === false) {
11746 // show a message if no listener is registered.
11747 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11748 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11750 // loadmask wil be hooked into this..
11751 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11754 var r = o.records, t = o.totalRecords || r.length;
11756 this.fireEvent("beforeloadadd", this, r, options, o);
11758 if(!options || options.add !== true){
11759 if(this.pruneModifiedRecords){
11760 this.modified = [];
11762 for(var i = 0, len = r.length; i < len; i++){
11766 this.data = this.snapshot;
11767 delete this.snapshot;
11770 this.data.addAll(r);
11771 this.totalLength = t;
11773 this.fireEvent("datachanged", this);
11775 this.totalLength = Math.max(t, this.data.length+r.length);
11779 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11781 var e = new Roo.data.Record({});
11783 e.set(this.parent.displayField, this.parent.emptyTitle);
11784 e.set(this.parent.valueField, '');
11789 this.fireEvent("load", this, r, options, o);
11790 if(options.callback){
11791 options.callback.call(options.scope || this, r, options, true);
11797 * Loads data from a passed data block. A Reader which understands the format of the data
11798 * must have been configured in the constructor.
11799 * @param {Object} data The data block from which to read the Records. The format of the data expected
11800 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11801 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11803 loadData : function(o, append){
11804 var r = this.reader.readRecords(o);
11805 this.loadRecords(r, {add: append}, true);
11809 * Gets the number of cached records.
11811 * <em>If using paging, this may not be the total size of the dataset. If the data object
11812 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11813 * the data set size</em>
11815 getCount : function(){
11816 return this.data.length || 0;
11820 * Gets the total number of records in the dataset as returned by the server.
11822 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11823 * the dataset size</em>
11825 getTotalCount : function(){
11826 return this.totalLength || 0;
11830 * Returns the sort state of the Store as an object with two properties:
11832 field {String} The name of the field by which the Records are sorted
11833 direction {String} The sort order, "ASC" or "DESC"
11836 getSortState : function(){
11837 return this.sortInfo;
11841 applySort : function(){
11842 if(this.sortInfo && !this.remoteSort){
11843 var s = this.sortInfo, f = s.field;
11844 var st = this.fields.get(f).sortType;
11845 var fn = function(r1, r2){
11846 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11847 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11849 this.data.sort(s.direction, fn);
11850 if(this.snapshot && this.snapshot != this.data){
11851 this.snapshot.sort(s.direction, fn);
11857 * Sets the default sort column and order to be used by the next load operation.
11858 * @param {String} fieldName The name of the field to sort by.
11859 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11861 setDefaultSort : function(field, dir){
11862 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11866 * Sort the Records.
11867 * If remote sorting is used, the sort is performed on the server, and the cache is
11868 * reloaded. If local sorting is used, the cache is sorted internally.
11869 * @param {String} fieldName The name of the field to sort by.
11870 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11872 sort : function(fieldName, dir){
11873 var f = this.fields.get(fieldName);
11875 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11877 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11878 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11883 this.sortToggle[f.name] = dir;
11884 this.sortInfo = {field: f.name, direction: dir};
11885 if(!this.remoteSort){
11887 this.fireEvent("datachanged", this);
11889 this.load(this.lastOptions);
11894 * Calls the specified function for each of the Records in the cache.
11895 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11896 * Returning <em>false</em> aborts and exits the iteration.
11897 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11899 each : function(fn, scope){
11900 this.data.each(fn, scope);
11904 * Gets all records modified since the last commit. Modified records are persisted across load operations
11905 * (e.g., during paging).
11906 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11908 getModifiedRecords : function(){
11909 return this.modified;
11913 createFilterFn : function(property, value, anyMatch){
11914 if(!value.exec){ // not a regex
11915 value = String(value);
11916 if(value.length == 0){
11919 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11921 return function(r){
11922 return value.test(r.data[property]);
11927 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11928 * @param {String} property A field on your records
11929 * @param {Number} start The record index to start at (defaults to 0)
11930 * @param {Number} end The last record index to include (defaults to length - 1)
11931 * @return {Number} The sum
11933 sum : function(property, start, end){
11934 var rs = this.data.items, v = 0;
11935 start = start || 0;
11936 end = (end || end === 0) ? end : rs.length-1;
11938 for(var i = start; i <= end; i++){
11939 v += (rs[i].data[property] || 0);
11945 * Filter the records by a specified property.
11946 * @param {String} field A field on your records
11947 * @param {String/RegExp} value Either a string that the field
11948 * should start with or a RegExp to test against the field
11949 * @param {Boolean} anyMatch True to match any part not just the beginning
11951 filter : function(property, value, anyMatch){
11952 var fn = this.createFilterFn(property, value, anyMatch);
11953 return fn ? this.filterBy(fn) : this.clearFilter();
11957 * Filter by a function. The specified function will be called with each
11958 * record in this data source. If the function returns true the record is included,
11959 * otherwise it is filtered.
11960 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11961 * @param {Object} scope (optional) The scope of the function (defaults to this)
11963 filterBy : function(fn, scope){
11964 this.snapshot = this.snapshot || this.data;
11965 this.data = this.queryBy(fn, scope||this);
11966 this.fireEvent("datachanged", this);
11970 * Query the records by a specified property.
11971 * @param {String} field A field on your records
11972 * @param {String/RegExp} value Either a string that the field
11973 * should start with or a RegExp to test against the field
11974 * @param {Boolean} anyMatch True to match any part not just the beginning
11975 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11977 query : function(property, value, anyMatch){
11978 var fn = this.createFilterFn(property, value, anyMatch);
11979 return fn ? this.queryBy(fn) : this.data.clone();
11983 * Query by a function. The specified function will be called with each
11984 * record in this data source. If the function returns true the record is included
11986 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11987 * @param {Object} scope (optional) The scope of the function (defaults to this)
11988 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11990 queryBy : function(fn, scope){
11991 var data = this.snapshot || this.data;
11992 return data.filterBy(fn, scope||this);
11996 * Collects unique values for a particular dataIndex from this store.
11997 * @param {String} dataIndex The property to collect
11998 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11999 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
12000 * @return {Array} An array of the unique values
12002 collect : function(dataIndex, allowNull, bypassFilter){
12003 var d = (bypassFilter === true && this.snapshot) ?
12004 this.snapshot.items : this.data.items;
12005 var v, sv, r = [], l = {};
12006 for(var i = 0, len = d.length; i < len; i++){
12007 v = d[i].data[dataIndex];
12009 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
12018 * Revert to a view of the Record cache with no filtering applied.
12019 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
12021 clearFilter : function(suppressEvent){
12022 if(this.snapshot && this.snapshot != this.data){
12023 this.data = this.snapshot;
12024 delete this.snapshot;
12025 if(suppressEvent !== true){
12026 this.fireEvent("datachanged", this);
12032 afterEdit : function(record){
12033 if(this.modified.indexOf(record) == -1){
12034 this.modified.push(record);
12036 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12040 afterReject : function(record){
12041 this.modified.remove(record);
12042 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12046 afterCommit : function(record){
12047 this.modified.remove(record);
12048 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12052 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12053 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12055 commitChanges : function(){
12056 var m = this.modified.slice(0);
12057 this.modified = [];
12058 for(var i = 0, len = m.length; i < len; i++){
12064 * Cancel outstanding changes on all changed records.
12066 rejectChanges : function(){
12067 var m = this.modified.slice(0);
12068 this.modified = [];
12069 for(var i = 0, len = m.length; i < len; i++){
12074 onMetaChange : function(meta, rtype, o){
12075 this.recordType = rtype;
12076 this.fields = rtype.prototype.fields;
12077 delete this.snapshot;
12078 this.sortInfo = meta.sortInfo || this.sortInfo;
12079 this.modified = [];
12080 this.fireEvent('metachange', this, this.reader.meta);
12083 moveIndex : function(data, type)
12085 var index = this.indexOf(data);
12087 var newIndex = index + type;
12091 this.insert(newIndex, data);
12096 * Ext JS Library 1.1.1
12097 * Copyright(c) 2006-2007, Ext JS, LLC.
12099 * Originally Released Under LGPL - original licence link has changed is not relivant.
12102 * <script type="text/javascript">
12106 * @class Roo.data.SimpleStore
12107 * @extends Roo.data.Store
12108 * Small helper class to make creating Stores from Array data easier.
12109 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12110 * @cfg {Array} fields An array of field definition objects, or field name strings.
12111 * @cfg {Array} data The multi-dimensional array of data
12113 * @param {Object} config
12115 Roo.data.SimpleStore = function(config){
12116 Roo.data.SimpleStore.superclass.constructor.call(this, {
12118 reader: new Roo.data.ArrayReader({
12121 Roo.data.Record.create(config.fields)
12123 proxy : new Roo.data.MemoryProxy(config.data)
12127 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12129 * Ext JS Library 1.1.1
12130 * Copyright(c) 2006-2007, Ext JS, LLC.
12132 * Originally Released Under LGPL - original licence link has changed is not relivant.
12135 * <script type="text/javascript">
12140 * @extends Roo.data.Store
12141 * @class Roo.data.JsonStore
12142 * Small helper class to make creating Stores for JSON data easier. <br/>
12144 var store = new Roo.data.JsonStore({
12145 url: 'get-images.php',
12147 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12150 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12151 * JsonReader and HttpProxy (unless inline data is provided).</b>
12152 * @cfg {Array} fields An array of field definition objects, or field name strings.
12154 * @param {Object} config
12156 Roo.data.JsonStore = function(c){
12157 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12158 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12159 reader: new Roo.data.JsonReader(c, c.fields)
12162 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12164 * Ext JS Library 1.1.1
12165 * Copyright(c) 2006-2007, Ext JS, LLC.
12167 * Originally Released Under LGPL - original licence link has changed is not relivant.
12170 * <script type="text/javascript">
12174 Roo.data.Field = function(config){
12175 if(typeof config == "string"){
12176 config = {name: config};
12178 Roo.apply(this, config);
12181 this.type = "auto";
12184 var st = Roo.data.SortTypes;
12185 // named sortTypes are supported, here we look them up
12186 if(typeof this.sortType == "string"){
12187 this.sortType = st[this.sortType];
12190 // set default sortType for strings and dates
12191 if(!this.sortType){
12194 this.sortType = st.asUCString;
12197 this.sortType = st.asDate;
12200 this.sortType = st.none;
12205 var stripRe = /[\$,%]/g;
12207 // prebuilt conversion function for this field, instead of
12208 // switching every time we're reading a value
12210 var cv, dateFormat = this.dateFormat;
12215 cv = function(v){ return v; };
12218 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12222 return v !== undefined && v !== null && v !== '' ?
12223 parseInt(String(v).replace(stripRe, ""), 10) : '';
12228 return v !== undefined && v !== null && v !== '' ?
12229 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12234 cv = function(v){ return v === true || v === "true" || v == 1; };
12241 if(v instanceof Date){
12245 if(dateFormat == "timestamp"){
12246 return new Date(v*1000);
12248 return Date.parseDate(v, dateFormat);
12250 var parsed = Date.parse(v);
12251 return parsed ? new Date(parsed) : null;
12260 Roo.data.Field.prototype = {
12268 * Ext JS Library 1.1.1
12269 * Copyright(c) 2006-2007, Ext JS, LLC.
12271 * Originally Released Under LGPL - original licence link has changed is not relivant.
12274 * <script type="text/javascript">
12277 // Base class for reading structured data from a data source. This class is intended to be
12278 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12281 * @class Roo.data.DataReader
12282 * Base class for reading structured data from a data source. This class is intended to be
12283 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12286 Roo.data.DataReader = function(meta, recordType){
12290 this.recordType = recordType instanceof Array ?
12291 Roo.data.Record.create(recordType) : recordType;
12294 Roo.data.DataReader.prototype = {
12296 * Create an empty record
12297 * @param {Object} data (optional) - overlay some values
12298 * @return {Roo.data.Record} record created.
12300 newRow : function(d) {
12302 this.recordType.prototype.fields.each(function(c) {
12304 case 'int' : da[c.name] = 0; break;
12305 case 'date' : da[c.name] = new Date(); break;
12306 case 'float' : da[c.name] = 0.0; break;
12307 case 'boolean' : da[c.name] = false; break;
12308 default : da[c.name] = ""; break;
12312 return new this.recordType(Roo.apply(da, d));
12317 * Ext JS Library 1.1.1
12318 * Copyright(c) 2006-2007, Ext JS, LLC.
12320 * Originally Released Under LGPL - original licence link has changed is not relivant.
12323 * <script type="text/javascript">
12327 * @class Roo.data.DataProxy
12328 * @extends Roo.data.Observable
12329 * This class is an abstract base class for implementations which provide retrieval of
12330 * unformatted data objects.<br>
12332 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12333 * (of the appropriate type which knows how to parse the data object) to provide a block of
12334 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12336 * Custom implementations must implement the load method as described in
12337 * {@link Roo.data.HttpProxy#load}.
12339 Roo.data.DataProxy = function(){
12342 * @event beforeload
12343 * Fires before a network request is made to retrieve a data object.
12344 * @param {Object} This DataProxy object.
12345 * @param {Object} params The params parameter to the load function.
12350 * Fires before the load method's callback is called.
12351 * @param {Object} This DataProxy object.
12352 * @param {Object} o The data object.
12353 * @param {Object} arg The callback argument object passed to the load function.
12357 * @event loadexception
12358 * Fires if an Exception occurs during data retrieval.
12359 * @param {Object} This DataProxy object.
12360 * @param {Object} o The data object.
12361 * @param {Object} arg The callback argument object passed to the load function.
12362 * @param {Object} e The Exception.
12364 loadexception : true
12366 Roo.data.DataProxy.superclass.constructor.call(this);
12369 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12372 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12376 * Ext JS Library 1.1.1
12377 * Copyright(c) 2006-2007, Ext JS, LLC.
12379 * Originally Released Under LGPL - original licence link has changed is not relivant.
12382 * <script type="text/javascript">
12385 * @class Roo.data.MemoryProxy
12386 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12387 * to the Reader when its load method is called.
12389 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12391 Roo.data.MemoryProxy = function(data){
12395 Roo.data.MemoryProxy.superclass.constructor.call(this);
12399 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12402 * Load data from the requested source (in this case an in-memory
12403 * data object passed to the constructor), read the data object into
12404 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12405 * process that block using the passed callback.
12406 * @param {Object} params This parameter is not used by the MemoryProxy class.
12407 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12408 * object into a block of Roo.data.Records.
12409 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12410 * The function must be passed <ul>
12411 * <li>The Record block object</li>
12412 * <li>The "arg" argument from the load function</li>
12413 * <li>A boolean success indicator</li>
12415 * @param {Object} scope The scope in which to call the callback
12416 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12418 load : function(params, reader, callback, scope, arg){
12419 params = params || {};
12422 result = reader.readRecords(params.data ? params.data :this.data);
12424 this.fireEvent("loadexception", this, arg, null, e);
12425 callback.call(scope, null, arg, false);
12428 callback.call(scope, result, arg, true);
12432 update : function(params, records){
12437 * Ext JS Library 1.1.1
12438 * Copyright(c) 2006-2007, Ext JS, LLC.
12440 * Originally Released Under LGPL - original licence link has changed is not relivant.
12443 * <script type="text/javascript">
12446 * @class Roo.data.HttpProxy
12447 * @extends Roo.data.DataProxy
12448 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12449 * configured to reference a certain URL.<br><br>
12451 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12452 * from which the running page was served.<br><br>
12454 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12456 * Be aware that to enable the browser to parse an XML document, the server must set
12457 * the Content-Type header in the HTTP response to "text/xml".
12459 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12460 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12461 * will be used to make the request.
12463 Roo.data.HttpProxy = function(conn){
12464 Roo.data.HttpProxy.superclass.constructor.call(this);
12465 // is conn a conn config or a real conn?
12467 this.useAjax = !conn || !conn.events;
12471 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12472 // thse are take from connection...
12475 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12478 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12479 * extra parameters to each request made by this object. (defaults to undefined)
12482 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12483 * to each request made by this object. (defaults to undefined)
12486 * @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)
12489 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12492 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12498 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12502 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12503 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12504 * a finer-grained basis than the DataProxy events.
12506 getConnection : function(){
12507 return this.useAjax ? Roo.Ajax : this.conn;
12511 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12512 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12513 * process that block using the passed callback.
12514 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12515 * for the request to the remote server.
12516 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12517 * object into a block of Roo.data.Records.
12518 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12519 * The function must be passed <ul>
12520 * <li>The Record block object</li>
12521 * <li>The "arg" argument from the load function</li>
12522 * <li>A boolean success indicator</li>
12524 * @param {Object} scope The scope in which to call the callback
12525 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12527 load : function(params, reader, callback, scope, arg){
12528 if(this.fireEvent("beforeload", this, params) !== false){
12530 params : params || {},
12532 callback : callback,
12537 callback : this.loadResponse,
12541 Roo.applyIf(o, this.conn);
12542 if(this.activeRequest){
12543 Roo.Ajax.abort(this.activeRequest);
12545 this.activeRequest = Roo.Ajax.request(o);
12547 this.conn.request(o);
12550 callback.call(scope||this, null, arg, false);
12555 loadResponse : function(o, success, response){
12556 delete this.activeRequest;
12558 this.fireEvent("loadexception", this, o, response);
12559 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12564 result = o.reader.read(response);
12566 this.fireEvent("loadexception", this, o, response, e);
12567 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12571 this.fireEvent("load", this, o, o.request.arg);
12572 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12576 update : function(dataSet){
12581 updateResponse : function(dataSet){
12586 * Ext JS Library 1.1.1
12587 * Copyright(c) 2006-2007, Ext JS, LLC.
12589 * Originally Released Under LGPL - original licence link has changed is not relivant.
12592 * <script type="text/javascript">
12596 * @class Roo.data.ScriptTagProxy
12597 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12598 * other than the originating domain of the running page.<br><br>
12600 * <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
12601 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12603 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12604 * source code that is used as the source inside a <script> tag.<br><br>
12606 * In order for the browser to process the returned data, the server must wrap the data object
12607 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12608 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12609 * depending on whether the callback name was passed:
12612 boolean scriptTag = false;
12613 String cb = request.getParameter("callback");
12616 response.setContentType("text/javascript");
12618 response.setContentType("application/x-json");
12620 Writer out = response.getWriter();
12622 out.write(cb + "(");
12624 out.print(dataBlock.toJsonString());
12631 * @param {Object} config A configuration object.
12633 Roo.data.ScriptTagProxy = function(config){
12634 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12635 Roo.apply(this, config);
12636 this.head = document.getElementsByTagName("head")[0];
12639 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12641 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12643 * @cfg {String} url The URL from which to request the data object.
12646 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12650 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12651 * the server the name of the callback function set up by the load call to process the returned data object.
12652 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12653 * javascript output which calls this named function passing the data object as its only parameter.
12655 callbackParam : "callback",
12657 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12658 * name to the request.
12663 * Load data from the configured URL, read the data object into
12664 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12665 * process that block using the passed callback.
12666 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12667 * for the request to the remote server.
12668 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12669 * object into a block of Roo.data.Records.
12670 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12671 * The function must be passed <ul>
12672 * <li>The Record block object</li>
12673 * <li>The "arg" argument from the load function</li>
12674 * <li>A boolean success indicator</li>
12676 * @param {Object} scope The scope in which to call the callback
12677 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12679 load : function(params, reader, callback, scope, arg){
12680 if(this.fireEvent("beforeload", this, params) !== false){
12682 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12684 var url = this.url;
12685 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12687 url += "&_dc=" + (new Date().getTime());
12689 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12692 cb : "stcCallback"+transId,
12693 scriptId : "stcScript"+transId,
12697 callback : callback,
12703 window[trans.cb] = function(o){
12704 conn.handleResponse(o, trans);
12707 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12709 if(this.autoAbort !== false){
12713 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12715 var script = document.createElement("script");
12716 script.setAttribute("src", url);
12717 script.setAttribute("type", "text/javascript");
12718 script.setAttribute("id", trans.scriptId);
12719 this.head.appendChild(script);
12721 this.trans = trans;
12723 callback.call(scope||this, null, arg, false);
12728 isLoading : function(){
12729 return this.trans ? true : false;
12733 * Abort the current server request.
12735 abort : function(){
12736 if(this.isLoading()){
12737 this.destroyTrans(this.trans);
12742 destroyTrans : function(trans, isLoaded){
12743 this.head.removeChild(document.getElementById(trans.scriptId));
12744 clearTimeout(trans.timeoutId);
12746 window[trans.cb] = undefined;
12748 delete window[trans.cb];
12751 // if hasn't been loaded, wait for load to remove it to prevent script error
12752 window[trans.cb] = function(){
12753 window[trans.cb] = undefined;
12755 delete window[trans.cb];
12762 handleResponse : function(o, trans){
12763 this.trans = false;
12764 this.destroyTrans(trans, true);
12767 result = trans.reader.readRecords(o);
12769 this.fireEvent("loadexception", this, o, trans.arg, e);
12770 trans.callback.call(trans.scope||window, null, trans.arg, false);
12773 this.fireEvent("load", this, o, trans.arg);
12774 trans.callback.call(trans.scope||window, result, trans.arg, true);
12778 handleFailure : function(trans){
12779 this.trans = false;
12780 this.destroyTrans(trans, false);
12781 this.fireEvent("loadexception", this, null, trans.arg);
12782 trans.callback.call(trans.scope||window, null, trans.arg, false);
12786 * Ext JS Library 1.1.1
12787 * Copyright(c) 2006-2007, Ext JS, LLC.
12789 * Originally Released Under LGPL - original licence link has changed is not relivant.
12792 * <script type="text/javascript">
12796 * @class Roo.data.JsonReader
12797 * @extends Roo.data.DataReader
12798 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12799 * based on mappings in a provided Roo.data.Record constructor.
12801 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12802 * in the reply previously.
12807 var RecordDef = Roo.data.Record.create([
12808 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12809 {name: 'occupation'} // This field will use "occupation" as the mapping.
12811 var myReader = new Roo.data.JsonReader({
12812 totalProperty: "results", // The property which contains the total dataset size (optional)
12813 root: "rows", // The property which contains an Array of row objects
12814 id: "id" // The property within each row object that provides an ID for the record (optional)
12818 * This would consume a JSON file like this:
12820 { 'results': 2, 'rows': [
12821 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12822 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12825 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12826 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12827 * paged from the remote server.
12828 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12829 * @cfg {String} root name of the property which contains the Array of row objects.
12830 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12831 * @cfg {Array} fields Array of field definition objects
12833 * Create a new JsonReader
12834 * @param {Object} meta Metadata configuration options
12835 * @param {Object} recordType Either an Array of field definition objects,
12836 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12838 Roo.data.JsonReader = function(meta, recordType){
12841 // set some defaults:
12842 Roo.applyIf(meta, {
12843 totalProperty: 'total',
12844 successProperty : 'success',
12849 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12851 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12854 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12855 * Used by Store query builder to append _requestMeta to params.
12858 metaFromRemote : false,
12860 * This method is only used by a DataProxy which has retrieved data from a remote server.
12861 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12862 * @return {Object} data A data block which is used by an Roo.data.Store object as
12863 * a cache of Roo.data.Records.
12865 read : function(response){
12866 var json = response.responseText;
12868 var o = /* eval:var:o */ eval("("+json+")");
12870 throw {message: "JsonReader.read: Json object not found"};
12876 this.metaFromRemote = true;
12877 this.meta = o.metaData;
12878 this.recordType = Roo.data.Record.create(o.metaData.fields);
12879 this.onMetaChange(this.meta, this.recordType, o);
12881 return this.readRecords(o);
12884 // private function a store will implement
12885 onMetaChange : function(meta, recordType, o){
12892 simpleAccess: function(obj, subsc) {
12899 getJsonAccessor: function(){
12901 return function(expr) {
12903 return(re.test(expr))
12904 ? new Function("obj", "return obj." + expr)
12909 return Roo.emptyFn;
12914 * Create a data block containing Roo.data.Records from an XML document.
12915 * @param {Object} o An object which contains an Array of row objects in the property specified
12916 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12917 * which contains the total size of the dataset.
12918 * @return {Object} data A data block which is used by an Roo.data.Store object as
12919 * a cache of Roo.data.Records.
12921 readRecords : function(o){
12923 * After any data loads, the raw JSON data is available for further custom processing.
12927 var s = this.meta, Record = this.recordType,
12928 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12930 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12932 if(s.totalProperty) {
12933 this.getTotal = this.getJsonAccessor(s.totalProperty);
12935 if(s.successProperty) {
12936 this.getSuccess = this.getJsonAccessor(s.successProperty);
12938 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12940 var g = this.getJsonAccessor(s.id);
12941 this.getId = function(rec) {
12943 return (r === undefined || r === "") ? null : r;
12946 this.getId = function(){return null;};
12949 for(var jj = 0; jj < fl; jj++){
12951 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12952 this.ef[jj] = this.getJsonAccessor(map);
12956 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12957 if(s.totalProperty){
12958 var vt = parseInt(this.getTotal(o), 10);
12963 if(s.successProperty){
12964 var vs = this.getSuccess(o);
12965 if(vs === false || vs === 'false'){
12970 for(var i = 0; i < c; i++){
12973 var id = this.getId(n);
12974 for(var j = 0; j < fl; j++){
12976 var v = this.ef[j](n);
12978 Roo.log('missing convert for ' + f.name);
12982 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12984 var record = new Record(values, id);
12986 records[i] = record;
12992 totalRecords : totalRecords
12997 * Ext JS Library 1.1.1
12998 * Copyright(c) 2006-2007, Ext JS, LLC.
13000 * Originally Released Under LGPL - original licence link has changed is not relivant.
13003 * <script type="text/javascript">
13007 * @class Roo.data.ArrayReader
13008 * @extends Roo.data.DataReader
13009 * Data reader class to create an Array of Roo.data.Record objects from an Array.
13010 * Each element of that Array represents a row of data fields. The
13011 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
13012 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
13016 var RecordDef = Roo.data.Record.create([
13017 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
13018 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
13020 var myReader = new Roo.data.ArrayReader({
13021 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
13025 * This would consume an Array like this:
13027 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
13031 * Create a new JsonReader
13032 * @param {Object} meta Metadata configuration options.
13033 * @param {Object|Array} recordType Either an Array of field definition objects
13035 * @cfg {Array} fields Array of field definition objects
13036 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
13037 * as specified to {@link Roo.data.Record#create},
13038 * or an {@link Roo.data.Record} object
13041 * created using {@link Roo.data.Record#create}.
13043 Roo.data.ArrayReader = function(meta, recordType){
13046 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13049 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13051 * Create a data block containing Roo.data.Records from an XML document.
13052 * @param {Object} o An Array of row objects which represents the dataset.
13053 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
13054 * a cache of Roo.data.Records.
13056 readRecords : function(o){
13057 var sid = this.meta ? this.meta.id : null;
13058 var recordType = this.recordType, fields = recordType.prototype.fields;
13061 for(var i = 0; i < root.length; i++){
13064 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13065 for(var j = 0, jlen = fields.length; j < jlen; j++){
13066 var f = fields.items[j];
13067 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13068 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13070 values[f.name] = v;
13072 var record = new recordType(values, id);
13074 records[records.length] = record;
13078 totalRecords : records.length
13087 * @class Roo.bootstrap.ComboBox
13088 * @extends Roo.bootstrap.TriggerField
13089 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13090 * @cfg {Boolean} append (true|false) default false
13091 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13092 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13093 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13094 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13095 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13096 * @cfg {Boolean} animate default true
13097 * @cfg {Boolean} emptyResultText only for touch device
13098 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13099 * @cfg {String} emptyTitle default ''
13101 * Create a new ComboBox.
13102 * @param {Object} config Configuration options
13104 Roo.bootstrap.ComboBox = function(config){
13105 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13109 * Fires when the dropdown list is expanded
13110 * @param {Roo.bootstrap.ComboBox} combo This combo box
13115 * Fires when the dropdown list is collapsed
13116 * @param {Roo.bootstrap.ComboBox} combo This combo box
13120 * @event beforeselect
13121 * Fires before a list item is selected. Return false to cancel the selection.
13122 * @param {Roo.bootstrap.ComboBox} combo This combo box
13123 * @param {Roo.data.Record} record The data record returned from the underlying store
13124 * @param {Number} index The index of the selected item in the dropdown list
13126 'beforeselect' : true,
13129 * Fires when a list item is selected
13130 * @param {Roo.bootstrap.ComboBox} combo This combo box
13131 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13132 * @param {Number} index The index of the selected item in the dropdown list
13136 * @event beforequery
13137 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13138 * The event object passed has these properties:
13139 * @param {Roo.bootstrap.ComboBox} combo This combo box
13140 * @param {String} query The query
13141 * @param {Boolean} forceAll true to force "all" query
13142 * @param {Boolean} cancel true to cancel the query
13143 * @param {Object} e The query event object
13145 'beforequery': true,
13148 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13149 * @param {Roo.bootstrap.ComboBox} combo This combo box
13154 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13155 * @param {Roo.bootstrap.ComboBox} combo This combo box
13156 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13161 * Fires when the remove value from the combobox array
13162 * @param {Roo.bootstrap.ComboBox} combo This combo box
13166 * @event afterremove
13167 * Fires when the remove value from the combobox array
13168 * @param {Roo.bootstrap.ComboBox} combo This combo box
13170 'afterremove' : true,
13172 * @event specialfilter
13173 * Fires when specialfilter
13174 * @param {Roo.bootstrap.ComboBox} combo This combo box
13176 'specialfilter' : true,
13179 * Fires when tick the element
13180 * @param {Roo.bootstrap.ComboBox} combo This combo box
13184 * @event touchviewdisplay
13185 * Fires when touch view require special display (default is using displayField)
13186 * @param {Roo.bootstrap.ComboBox} combo This combo box
13187 * @param {Object} cfg set html .
13189 'touchviewdisplay' : true
13194 this.tickItems = [];
13196 this.selectedIndex = -1;
13197 if(this.mode == 'local'){
13198 if(config.queryDelay === undefined){
13199 this.queryDelay = 10;
13201 if(config.minChars === undefined){
13207 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13210 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13211 * rendering into an Roo.Editor, defaults to false)
13214 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13215 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13218 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13221 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13222 * the dropdown list (defaults to undefined, with no header element)
13226 * @cfg {String/Roo.Template} tpl The template to use to render the output
13230 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13232 listWidth: undefined,
13234 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13235 * mode = 'remote' or 'text' if mode = 'local')
13237 displayField: undefined,
13240 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13241 * mode = 'remote' or 'value' if mode = 'local').
13242 * Note: use of a valueField requires the user make a selection
13243 * in order for a value to be mapped.
13245 valueField: undefined,
13247 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13252 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13253 * field's data value (defaults to the underlying DOM element's name)
13255 hiddenName: undefined,
13257 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13261 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13263 selectedClass: 'active',
13266 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13270 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13271 * anchor positions (defaults to 'tl-bl')
13273 listAlign: 'tl-bl?',
13275 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13279 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13280 * query specified by the allQuery config option (defaults to 'query')
13282 triggerAction: 'query',
13284 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13285 * (defaults to 4, does not apply if editable = false)
13289 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13290 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13294 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13295 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13299 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13300 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13304 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13305 * when editable = true (defaults to false)
13307 selectOnFocus:false,
13309 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13311 queryParam: 'query',
13313 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13314 * when mode = 'remote' (defaults to 'Loading...')
13316 loadingText: 'Loading...',
13318 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13322 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13326 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13327 * traditional select (defaults to true)
13331 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13335 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13339 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13340 * listWidth has a higher value)
13344 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13345 * allow the user to set arbitrary text into the field (defaults to false)
13347 forceSelection:false,
13349 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13350 * if typeAhead = true (defaults to 250)
13352 typeAheadDelay : 250,
13354 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13355 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13357 valueNotFoundText : undefined,
13359 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13361 blockFocus : false,
13364 * @cfg {Boolean} disableClear Disable showing of clear button.
13366 disableClear : false,
13368 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13370 alwaysQuery : false,
13373 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13378 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13380 invalidClass : "has-warning",
13383 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13385 validClass : "has-success",
13388 * @cfg {Boolean} specialFilter (true|false) special filter default false
13390 specialFilter : false,
13393 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13395 mobileTouchView : true,
13398 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13400 useNativeIOS : false,
13403 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13405 mobile_restrict_height : false,
13407 ios_options : false,
13419 btnPosition : 'right',
13420 triggerList : true,
13421 showToggleBtn : true,
13423 emptyResultText: 'Empty',
13424 triggerText : 'Select',
13427 // element that contains real text value.. (when hidden is used..)
13429 getAutoCreate : function()
13434 * Render classic select for iso
13437 if(Roo.isIOS && this.useNativeIOS){
13438 cfg = this.getAutoCreateNativeIOS();
13446 if(Roo.isTouch && this.mobileTouchView){
13447 cfg = this.getAutoCreateTouchView();
13454 if(!this.tickable){
13455 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13460 * ComboBox with tickable selections
13463 var align = this.labelAlign || this.parentLabelAlign();
13466 cls : 'form-group roo-combobox-tickable' //input-group
13469 var btn_text_select = '';
13470 var btn_text_done = '';
13471 var btn_text_cancel = '';
13473 if (this.btn_text_show) {
13474 btn_text_select = 'Select';
13475 btn_text_done = 'Done';
13476 btn_text_cancel = 'Cancel';
13481 cls : 'tickable-buttons',
13486 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13487 //html : this.triggerText
13488 html: btn_text_select
13494 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13496 html: btn_text_done
13502 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13504 html: btn_text_cancel
13510 buttons.cn.unshift({
13512 cls: 'roo-select2-search-field-input'
13518 Roo.each(buttons.cn, function(c){
13520 c.cls += ' btn-' + _this.size;
13523 if (_this.disabled) {
13530 style : 'display: contents',
13535 cls: 'form-hidden-field'
13539 cls: 'roo-select2-choices',
13543 cls: 'roo-select2-search-field',
13554 cls: 'roo-select2-container input-group roo-select2-container-multi',
13560 // cls: 'typeahead typeahead-long dropdown-menu',
13561 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13566 if(this.hasFeedback && !this.allowBlank){
13570 cls: 'glyphicon form-control-feedback'
13573 combobox.cn.push(feedback);
13578 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13579 tooltip : 'This field is required'
13581 if (Roo.bootstrap.version == 4) {
13584 style : 'display:none'
13587 if (align ==='left' && this.fieldLabel.length) {
13589 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13596 cls : 'control-label col-form-label',
13597 html : this.fieldLabel
13609 var labelCfg = cfg.cn[1];
13610 var contentCfg = cfg.cn[2];
13613 if(this.indicatorpos == 'right'){
13619 cls : 'control-label col-form-label',
13623 html : this.fieldLabel
13639 labelCfg = cfg.cn[0];
13640 contentCfg = cfg.cn[1];
13644 if(this.labelWidth > 12){
13645 labelCfg.style = "width: " + this.labelWidth + 'px';
13648 if(this.labelWidth < 13 && this.labelmd == 0){
13649 this.labelmd = this.labelWidth;
13652 if(this.labellg > 0){
13653 labelCfg.cls += ' col-lg-' + this.labellg;
13654 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13657 if(this.labelmd > 0){
13658 labelCfg.cls += ' col-md-' + this.labelmd;
13659 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13662 if(this.labelsm > 0){
13663 labelCfg.cls += ' col-sm-' + this.labelsm;
13664 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13667 if(this.labelxs > 0){
13668 labelCfg.cls += ' col-xs-' + this.labelxs;
13669 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13673 } else if ( this.fieldLabel.length) {
13674 // Roo.log(" label");
13679 //cls : 'input-group-addon',
13680 html : this.fieldLabel
13685 if(this.indicatorpos == 'right'){
13689 //cls : 'input-group-addon',
13690 html : this.fieldLabel
13700 // Roo.log(" no label && no align");
13707 ['xs','sm','md','lg'].map(function(size){
13708 if (settings[size]) {
13709 cfg.cls += ' col-' + size + '-' + settings[size];
13717 _initEventsCalled : false,
13720 initEvents: function()
13722 if (this._initEventsCalled) { // as we call render... prevent looping...
13725 this._initEventsCalled = true;
13728 throw "can not find store for combo";
13731 this.indicator = this.indicatorEl();
13733 this.store = Roo.factory(this.store, Roo.data);
13734 this.store.parent = this;
13736 // if we are building from html. then this element is so complex, that we can not really
13737 // use the rendered HTML.
13738 // so we have to trash and replace the previous code.
13739 if (Roo.XComponent.build_from_html) {
13740 // remove this element....
13741 var e = this.el.dom, k=0;
13742 while (e ) { e = e.previousSibling; ++k;}
13747 this.rendered = false;
13749 this.render(this.parent().getChildContainer(true), k);
13752 if(Roo.isIOS && this.useNativeIOS){
13753 this.initIOSView();
13761 if(Roo.isTouch && this.mobileTouchView){
13762 this.initTouchView();
13767 this.initTickableEvents();
13771 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13773 if(this.hiddenName){
13775 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13777 this.hiddenField.dom.value =
13778 this.hiddenValue !== undefined ? this.hiddenValue :
13779 this.value !== undefined ? this.value : '';
13781 // prevent input submission
13782 this.el.dom.removeAttribute('name');
13783 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13788 // this.el.dom.setAttribute('autocomplete', 'off');
13791 var cls = 'x-combo-list';
13793 //this.list = new Roo.Layer({
13794 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13800 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13801 _this.list.setWidth(lw);
13804 this.list.on('mouseover', this.onViewOver, this);
13805 this.list.on('mousemove', this.onViewMove, this);
13806 this.list.on('scroll', this.onViewScroll, this);
13809 this.list.swallowEvent('mousewheel');
13810 this.assetHeight = 0;
13813 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13814 this.assetHeight += this.header.getHeight();
13817 this.innerList = this.list.createChild({cls:cls+'-inner'});
13818 this.innerList.on('mouseover', this.onViewOver, this);
13819 this.innerList.on('mousemove', this.onViewMove, this);
13820 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13822 if(this.allowBlank && !this.pageSize && !this.disableClear){
13823 this.footer = this.list.createChild({cls:cls+'-ft'});
13824 this.pageTb = new Roo.Toolbar(this.footer);
13828 this.footer = this.list.createChild({cls:cls+'-ft'});
13829 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13830 {pageSize: this.pageSize});
13834 if (this.pageTb && this.allowBlank && !this.disableClear) {
13836 this.pageTb.add(new Roo.Toolbar.Fill(), {
13837 cls: 'x-btn-icon x-btn-clear',
13839 handler: function()
13842 _this.clearValue();
13843 _this.onSelect(false, -1);
13848 this.assetHeight += this.footer.getHeight();
13853 this.tpl = Roo.bootstrap.version == 4 ?
13854 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13855 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13858 this.view = new Roo.View(this.list, this.tpl, {
13859 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13861 //this.view.wrapEl.setDisplayed(false);
13862 this.view.on('click', this.onViewClick, this);
13865 this.store.on('beforeload', this.onBeforeLoad, this);
13866 this.store.on('load', this.onLoad, this);
13867 this.store.on('loadexception', this.onLoadException, this);
13869 if(this.resizable){
13870 this.resizer = new Roo.Resizable(this.list, {
13871 pinned:true, handles:'se'
13873 this.resizer.on('resize', function(r, w, h){
13874 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13875 this.listWidth = w;
13876 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13877 this.restrictHeight();
13879 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13882 if(!this.editable){
13883 this.editable = true;
13884 this.setEditable(false);
13889 if (typeof(this.events.add.listeners) != 'undefined') {
13891 this.addicon = this.wrap.createChild(
13892 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13894 this.addicon.on('click', function(e) {
13895 this.fireEvent('add', this);
13898 if (typeof(this.events.edit.listeners) != 'undefined') {
13900 this.editicon = this.wrap.createChild(
13901 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13902 if (this.addicon) {
13903 this.editicon.setStyle('margin-left', '40px');
13905 this.editicon.on('click', function(e) {
13907 // we fire even if inothing is selected..
13908 this.fireEvent('edit', this, this.lastData );
13914 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13915 "up" : function(e){
13916 this.inKeyMode = true;
13920 "down" : function(e){
13921 if(!this.isExpanded()){
13922 this.onTriggerClick();
13924 this.inKeyMode = true;
13929 "enter" : function(e){
13930 // this.onViewClick();
13934 if(this.fireEvent("specialkey", this, e)){
13935 this.onViewClick(false);
13941 "esc" : function(e){
13945 "tab" : function(e){
13948 if(this.fireEvent("specialkey", this, e)){
13949 this.onViewClick(false);
13957 doRelay : function(foo, bar, hname){
13958 if(hname == 'down' || this.scope.isExpanded()){
13959 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13968 this.queryDelay = Math.max(this.queryDelay || 10,
13969 this.mode == 'local' ? 10 : 250);
13972 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13974 if(this.typeAhead){
13975 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13977 if(this.editable !== false){
13978 this.inputEl().on("keyup", this.onKeyUp, this);
13980 if(this.forceSelection){
13981 this.inputEl().on('blur', this.doForce, this);
13985 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13986 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13990 initTickableEvents: function()
13994 if(this.hiddenName){
13996 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13998 this.hiddenField.dom.value =
13999 this.hiddenValue !== undefined ? this.hiddenValue :
14000 this.value !== undefined ? this.value : '';
14002 // prevent input submission
14003 this.el.dom.removeAttribute('name');
14004 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14009 // this.list = this.el.select('ul.dropdown-menu',true).first();
14011 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14012 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14013 if(this.triggerList){
14014 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
14017 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
14018 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
14020 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
14021 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
14023 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
14024 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
14026 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
14027 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
14028 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
14031 this.cancelBtn.hide();
14036 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14037 _this.list.setWidth(lw);
14040 this.list.on('mouseover', this.onViewOver, this);
14041 this.list.on('mousemove', this.onViewMove, this);
14043 this.list.on('scroll', this.onViewScroll, this);
14046 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14047 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14050 this.view = new Roo.View(this.list, this.tpl, {
14055 selectedClass: this.selectedClass
14058 //this.view.wrapEl.setDisplayed(false);
14059 this.view.on('click', this.onViewClick, this);
14063 this.store.on('beforeload', this.onBeforeLoad, this);
14064 this.store.on('load', this.onLoad, this);
14065 this.store.on('loadexception', this.onLoadException, this);
14068 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14069 "up" : function(e){
14070 this.inKeyMode = true;
14074 "down" : function(e){
14075 this.inKeyMode = true;
14079 "enter" : function(e){
14080 if(this.fireEvent("specialkey", this, e)){
14081 this.onViewClick(false);
14087 "esc" : function(e){
14088 this.onTickableFooterButtonClick(e, false, false);
14091 "tab" : function(e){
14092 this.fireEvent("specialkey", this, e);
14094 this.onTickableFooterButtonClick(e, false, false);
14101 doRelay : function(e, fn, key){
14102 if(this.scope.isExpanded()){
14103 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14112 this.queryDelay = Math.max(this.queryDelay || 10,
14113 this.mode == 'local' ? 10 : 250);
14116 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14118 if(this.typeAhead){
14119 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14122 if(this.editable !== false){
14123 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14126 this.indicator = this.indicatorEl();
14128 if(this.indicator){
14129 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14130 this.indicator.hide();
14135 onDestroy : function(){
14137 this.view.setStore(null);
14138 this.view.el.removeAllListeners();
14139 this.view.el.remove();
14140 this.view.purgeListeners();
14143 this.list.dom.innerHTML = '';
14147 this.store.un('beforeload', this.onBeforeLoad, this);
14148 this.store.un('load', this.onLoad, this);
14149 this.store.un('loadexception', this.onLoadException, this);
14151 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14155 fireKey : function(e){
14156 if(e.isNavKeyPress() && !this.list.isVisible()){
14157 this.fireEvent("specialkey", this, e);
14162 onResize: function(w, h){
14163 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14165 // if(typeof w != 'number'){
14166 // // we do not handle it!?!?
14169 // var tw = this.trigger.getWidth();
14170 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14171 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14173 // this.inputEl().setWidth( this.adjustWidth('input', x));
14175 // //this.trigger.setStyle('left', x+'px');
14177 // if(this.list && this.listWidth === undefined){
14178 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14179 // this.list.setWidth(lw);
14180 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14188 * Allow or prevent the user from directly editing the field text. If false is passed,
14189 * the user will only be able to select from the items defined in the dropdown list. This method
14190 * is the runtime equivalent of setting the 'editable' config option at config time.
14191 * @param {Boolean} value True to allow the user to directly edit the field text
14193 setEditable : function(value){
14194 if(value == this.editable){
14197 this.editable = value;
14199 this.inputEl().dom.setAttribute('readOnly', true);
14200 this.inputEl().on('mousedown', this.onTriggerClick, this);
14201 this.inputEl().addClass('x-combo-noedit');
14203 this.inputEl().dom.setAttribute('readOnly', false);
14204 this.inputEl().un('mousedown', this.onTriggerClick, this);
14205 this.inputEl().removeClass('x-combo-noedit');
14211 onBeforeLoad : function(combo,opts){
14212 if(!this.hasFocus){
14216 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14218 this.restrictHeight();
14219 this.selectedIndex = -1;
14223 onLoad : function(){
14225 this.hasQuery = false;
14227 if(!this.hasFocus){
14231 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14232 this.loading.hide();
14235 if(this.store.getCount() > 0){
14238 this.restrictHeight();
14239 if(this.lastQuery == this.allQuery){
14240 if(this.editable && !this.tickable){
14241 this.inputEl().dom.select();
14245 !this.selectByValue(this.value, true) &&
14248 !this.store.lastOptions ||
14249 typeof(this.store.lastOptions.add) == 'undefined' ||
14250 this.store.lastOptions.add != true
14253 this.select(0, true);
14256 if(this.autoFocus){
14259 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14260 this.taTask.delay(this.typeAheadDelay);
14264 this.onEmptyResults();
14270 onLoadException : function()
14272 this.hasQuery = false;
14274 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14275 this.loading.hide();
14278 if(this.tickable && this.editable){
14283 // only causes errors at present
14284 //Roo.log(this.store.reader.jsonData);
14285 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14287 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14293 onTypeAhead : function(){
14294 if(this.store.getCount() > 0){
14295 var r = this.store.getAt(0);
14296 var newValue = r.data[this.displayField];
14297 var len = newValue.length;
14298 var selStart = this.getRawValue().length;
14300 if(selStart != len){
14301 this.setRawValue(newValue);
14302 this.selectText(selStart, newValue.length);
14308 onSelect : function(record, index){
14310 if(this.fireEvent('beforeselect', this, record, index) !== false){
14312 this.setFromData(index > -1 ? record.data : false);
14315 this.fireEvent('select', this, record, index);
14320 * Returns the currently selected field value or empty string if no value is set.
14321 * @return {String} value The selected value
14323 getValue : function()
14325 if(Roo.isIOS && this.useNativeIOS){
14326 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14330 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14333 if(this.valueField){
14334 return typeof this.value != 'undefined' ? this.value : '';
14336 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14340 getRawValue : function()
14342 if(Roo.isIOS && this.useNativeIOS){
14343 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14346 var v = this.inputEl().getValue();
14352 * Clears any text/value currently set in the field
14354 clearValue : function(){
14356 if(this.hiddenField){
14357 this.hiddenField.dom.value = '';
14360 this.setRawValue('');
14361 this.lastSelectionText = '';
14362 this.lastData = false;
14364 var close = this.closeTriggerEl();
14375 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14376 * will be displayed in the field. If the value does not match the data value of an existing item,
14377 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14378 * Otherwise the field will be blank (although the value will still be set).
14379 * @param {String} value The value to match
14381 setValue : function(v)
14383 if(Roo.isIOS && this.useNativeIOS){
14384 this.setIOSValue(v);
14394 if(this.valueField){
14395 var r = this.findRecord(this.valueField, v);
14397 text = r.data[this.displayField];
14398 }else if(this.valueNotFoundText !== undefined){
14399 text = this.valueNotFoundText;
14402 this.lastSelectionText = text;
14403 if(this.hiddenField){
14404 this.hiddenField.dom.value = v;
14406 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14409 var close = this.closeTriggerEl();
14412 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14418 * @property {Object} the last set data for the element
14423 * Sets the value of the field based on a object which is related to the record format for the store.
14424 * @param {Object} value the value to set as. or false on reset?
14426 setFromData : function(o){
14433 var dv = ''; // display value
14434 var vv = ''; // value value..
14436 if (this.displayField) {
14437 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14439 // this is an error condition!!!
14440 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14443 if(this.valueField){
14444 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14447 var close = this.closeTriggerEl();
14450 if(dv.length || vv * 1 > 0){
14452 this.blockFocus=true;
14458 if(this.hiddenField){
14459 this.hiddenField.dom.value = vv;
14461 this.lastSelectionText = dv;
14462 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14466 // no hidden field.. - we store the value in 'value', but still display
14467 // display field!!!!
14468 this.lastSelectionText = dv;
14469 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14476 reset : function(){
14477 // overridden so that last data is reset..
14484 this.setValue(this.originalValue);
14485 //this.clearInvalid();
14486 this.lastData = false;
14488 this.view.clearSelections();
14494 findRecord : function(prop, value){
14496 if(this.store.getCount() > 0){
14497 this.store.each(function(r){
14498 if(r.data[prop] == value){
14508 getName: function()
14510 // returns hidden if it's set..
14511 if (!this.rendered) {return ''};
14512 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14516 onViewMove : function(e, t){
14517 this.inKeyMode = false;
14521 onViewOver : function(e, t){
14522 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14525 var item = this.view.findItemFromChild(t);
14528 var index = this.view.indexOf(item);
14529 this.select(index, false);
14534 onViewClick : function(view, doFocus, el, e)
14536 var index = this.view.getSelectedIndexes()[0];
14538 var r = this.store.getAt(index);
14542 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14549 Roo.each(this.tickItems, function(v,k){
14551 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14553 _this.tickItems.splice(k, 1);
14555 if(typeof(e) == 'undefined' && view == false){
14556 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14568 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14569 this.tickItems.push(r.data);
14572 if(typeof(e) == 'undefined' && view == false){
14573 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14580 this.onSelect(r, index);
14582 if(doFocus !== false && !this.blockFocus){
14583 this.inputEl().focus();
14588 restrictHeight : function(){
14589 //this.innerList.dom.style.height = '';
14590 //var inner = this.innerList.dom;
14591 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14592 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14593 //this.list.beginUpdate();
14594 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14595 this.list.alignTo(this.inputEl(), this.listAlign);
14596 this.list.alignTo(this.inputEl(), this.listAlign);
14597 //this.list.endUpdate();
14601 onEmptyResults : function(){
14603 if(this.tickable && this.editable){
14604 this.hasFocus = false;
14605 this.restrictHeight();
14613 * Returns true if the dropdown list is expanded, else false.
14615 isExpanded : function(){
14616 return this.list.isVisible();
14620 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14621 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14622 * @param {String} value The data value of the item to select
14623 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14624 * selected item if it is not currently in view (defaults to true)
14625 * @return {Boolean} True if the value matched an item in the list, else false
14627 selectByValue : function(v, scrollIntoView){
14628 if(v !== undefined && v !== null){
14629 var r = this.findRecord(this.valueField || this.displayField, v);
14631 this.select(this.store.indexOf(r), scrollIntoView);
14639 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14640 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14641 * @param {Number} index The zero-based index of the list item to select
14642 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14643 * selected item if it is not currently in view (defaults to true)
14645 select : function(index, scrollIntoView){
14646 this.selectedIndex = index;
14647 this.view.select(index);
14648 if(scrollIntoView !== false){
14649 var el = this.view.getNode(index);
14651 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14654 this.list.scrollChildIntoView(el, false);
14660 selectNext : function(){
14661 var ct = this.store.getCount();
14663 if(this.selectedIndex == -1){
14665 }else if(this.selectedIndex < ct-1){
14666 this.select(this.selectedIndex+1);
14672 selectPrev : function(){
14673 var ct = this.store.getCount();
14675 if(this.selectedIndex == -1){
14677 }else if(this.selectedIndex != 0){
14678 this.select(this.selectedIndex-1);
14684 onKeyUp : function(e){
14685 if(this.editable !== false && !e.isSpecialKey()){
14686 this.lastKey = e.getKey();
14687 this.dqTask.delay(this.queryDelay);
14692 validateBlur : function(){
14693 return !this.list || !this.list.isVisible();
14697 initQuery : function(){
14699 var v = this.getRawValue();
14701 if(this.tickable && this.editable){
14702 v = this.tickableInputEl().getValue();
14709 doForce : function(){
14710 if(this.inputEl().dom.value.length > 0){
14711 this.inputEl().dom.value =
14712 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14718 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14719 * query allowing the query action to be canceled if needed.
14720 * @param {String} query The SQL query to execute
14721 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14722 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14723 * saved in the current store (defaults to false)
14725 doQuery : function(q, forceAll){
14727 if(q === undefined || q === null){
14732 forceAll: forceAll,
14736 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14741 forceAll = qe.forceAll;
14742 if(forceAll === true || (q.length >= this.minChars)){
14744 this.hasQuery = true;
14746 if(this.lastQuery != q || this.alwaysQuery){
14747 this.lastQuery = q;
14748 if(this.mode == 'local'){
14749 this.selectedIndex = -1;
14751 this.store.clearFilter();
14754 if(this.specialFilter){
14755 this.fireEvent('specialfilter', this);
14760 this.store.filter(this.displayField, q);
14763 this.store.fireEvent("datachanged", this.store);
14770 this.store.baseParams[this.queryParam] = q;
14772 var options = {params : this.getParams(q)};
14775 options.add = true;
14776 options.params.start = this.page * this.pageSize;
14779 this.store.load(options);
14782 * this code will make the page width larger, at the beginning, the list not align correctly,
14783 * we should expand the list on onLoad
14784 * so command out it
14789 this.selectedIndex = -1;
14794 this.loadNext = false;
14798 getParams : function(q){
14800 //p[this.queryParam] = q;
14804 p.limit = this.pageSize;
14810 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14812 collapse : function(){
14813 if(!this.isExpanded()){
14819 this.hasFocus = false;
14823 this.cancelBtn.hide();
14824 this.trigger.show();
14827 this.tickableInputEl().dom.value = '';
14828 this.tickableInputEl().blur();
14833 Roo.get(document).un('mousedown', this.collapseIf, this);
14834 Roo.get(document).un('mousewheel', this.collapseIf, this);
14835 if (!this.editable) {
14836 Roo.get(document).un('keydown', this.listKeyPress, this);
14838 this.fireEvent('collapse', this);
14844 collapseIf : function(e){
14845 var in_combo = e.within(this.el);
14846 var in_list = e.within(this.list);
14847 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14849 if (in_combo || in_list || is_list) {
14850 //e.stopPropagation();
14855 this.onTickableFooterButtonClick(e, false, false);
14863 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14865 expand : function(){
14867 if(this.isExpanded() || !this.hasFocus){
14871 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14872 this.list.setWidth(lw);
14878 this.restrictHeight();
14882 this.tickItems = Roo.apply([], this.item);
14885 this.cancelBtn.show();
14886 this.trigger.hide();
14889 this.tickableInputEl().focus();
14894 Roo.get(document).on('mousedown', this.collapseIf, this);
14895 Roo.get(document).on('mousewheel', this.collapseIf, this);
14896 if (!this.editable) {
14897 Roo.get(document).on('keydown', this.listKeyPress, this);
14900 this.fireEvent('expand', this);
14904 // Implements the default empty TriggerField.onTriggerClick function
14905 onTriggerClick : function(e)
14907 Roo.log('trigger click');
14909 if(this.disabled || !this.triggerList){
14914 this.loadNext = false;
14916 if(this.isExpanded()){
14918 if (!this.blockFocus) {
14919 this.inputEl().focus();
14923 this.hasFocus = true;
14924 if(this.triggerAction == 'all') {
14925 this.doQuery(this.allQuery, true);
14927 this.doQuery(this.getRawValue());
14929 if (!this.blockFocus) {
14930 this.inputEl().focus();
14935 onTickableTriggerClick : function(e)
14942 this.loadNext = false;
14943 this.hasFocus = true;
14945 if(this.triggerAction == 'all') {
14946 this.doQuery(this.allQuery, true);
14948 this.doQuery(this.getRawValue());
14952 onSearchFieldClick : function(e)
14954 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14955 this.onTickableFooterButtonClick(e, false, false);
14959 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14964 this.loadNext = false;
14965 this.hasFocus = true;
14967 if(this.triggerAction == 'all') {
14968 this.doQuery(this.allQuery, true);
14970 this.doQuery(this.getRawValue());
14974 listKeyPress : function(e)
14976 //Roo.log('listkeypress');
14977 // scroll to first matching element based on key pres..
14978 if (e.isSpecialKey()) {
14981 var k = String.fromCharCode(e.getKey()).toUpperCase();
14984 var csel = this.view.getSelectedNodes();
14985 var cselitem = false;
14987 var ix = this.view.indexOf(csel[0]);
14988 cselitem = this.store.getAt(ix);
14989 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14995 this.store.each(function(v) {
14997 // start at existing selection.
14998 if (cselitem.id == v.id) {
15004 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
15005 match = this.store.indexOf(v);
15011 if (match === false) {
15012 return true; // no more action?
15015 this.view.select(match);
15016 var sn = Roo.get(this.view.getSelectedNodes()[0]);
15017 sn.scrollIntoView(sn.dom.parentNode, false);
15020 onViewScroll : function(e, t){
15022 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){
15026 this.hasQuery = true;
15028 this.loading = this.list.select('.loading', true).first();
15030 if(this.loading === null){
15031 this.list.createChild({
15033 cls: 'loading roo-select2-more-results roo-select2-active',
15034 html: 'Loading more results...'
15037 this.loading = this.list.select('.loading', true).first();
15039 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
15041 this.loading.hide();
15044 this.loading.show();
15049 this.loadNext = true;
15051 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15056 addItem : function(o)
15058 var dv = ''; // display value
15060 if (this.displayField) {
15061 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15063 // this is an error condition!!!
15064 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15071 var choice = this.choices.createChild({
15073 cls: 'roo-select2-search-choice',
15082 cls: 'roo-select2-search-choice-close fa fa-times',
15087 }, this.searchField);
15089 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15091 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15099 this.inputEl().dom.value = '';
15104 onRemoveItem : function(e, _self, o)
15106 e.preventDefault();
15108 this.lastItem = Roo.apply([], this.item);
15110 var index = this.item.indexOf(o.data) * 1;
15113 Roo.log('not this item?!');
15117 this.item.splice(index, 1);
15122 this.fireEvent('remove', this, e);
15128 syncValue : function()
15130 if(!this.item.length){
15137 Roo.each(this.item, function(i){
15138 if(_this.valueField){
15139 value.push(i[_this.valueField]);
15146 this.value = value.join(',');
15148 if(this.hiddenField){
15149 this.hiddenField.dom.value = this.value;
15152 this.store.fireEvent("datachanged", this.store);
15157 clearItem : function()
15159 if(!this.multiple){
15165 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15173 if(this.tickable && !Roo.isTouch){
15174 this.view.refresh();
15178 inputEl: function ()
15180 if(Roo.isIOS && this.useNativeIOS){
15181 return this.el.select('select.roo-ios-select', true).first();
15184 if(Roo.isTouch && this.mobileTouchView){
15185 return this.el.select('input.form-control',true).first();
15189 return this.searchField;
15192 return this.el.select('input.form-control',true).first();
15195 onTickableFooterButtonClick : function(e, btn, el)
15197 e.preventDefault();
15199 this.lastItem = Roo.apply([], this.item);
15201 if(btn && btn.name == 'cancel'){
15202 this.tickItems = Roo.apply([], this.item);
15211 Roo.each(this.tickItems, function(o){
15219 validate : function()
15221 if(this.getVisibilityEl().hasClass('hidden')){
15225 var v = this.getRawValue();
15228 v = this.getValue();
15231 if(this.disabled || this.allowBlank || v.length){
15236 this.markInvalid();
15240 tickableInputEl : function()
15242 if(!this.tickable || !this.editable){
15243 return this.inputEl();
15246 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15250 getAutoCreateTouchView : function()
15255 cls: 'form-group' //input-group
15261 type : this.inputType,
15262 cls : 'form-control x-combo-noedit',
15263 autocomplete: 'new-password',
15264 placeholder : this.placeholder || '',
15269 input.name = this.name;
15273 input.cls += ' input-' + this.size;
15276 if (this.disabled) {
15277 input.disabled = true;
15288 inputblock.cls += ' input-group';
15290 inputblock.cn.unshift({
15292 cls : 'input-group-addon input-group-prepend input-group-text',
15297 if(this.removable && !this.multiple){
15298 inputblock.cls += ' roo-removable';
15300 inputblock.cn.push({
15303 cls : 'roo-combo-removable-btn close'
15307 if(this.hasFeedback && !this.allowBlank){
15309 inputblock.cls += ' has-feedback';
15311 inputblock.cn.push({
15313 cls: 'glyphicon form-control-feedback'
15320 inputblock.cls += (this.before) ? '' : ' input-group';
15322 inputblock.cn.push({
15324 cls : 'input-group-addon input-group-append input-group-text',
15330 var ibwrap = inputblock;
15335 cls: 'roo-select2-choices',
15339 cls: 'roo-select2-search-field',
15352 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15357 cls: 'form-hidden-field'
15363 if(!this.multiple && this.showToggleBtn){
15370 if (this.caret != false) {
15373 cls: 'fa fa-' + this.caret
15380 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15385 cls: 'combobox-clear',
15399 combobox.cls += ' roo-select2-container-multi';
15402 var align = this.labelAlign || this.parentLabelAlign();
15404 if (align ==='left' && this.fieldLabel.length) {
15409 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15410 tooltip : 'This field is required'
15414 cls : 'control-label col-form-label',
15415 html : this.fieldLabel
15426 var labelCfg = cfg.cn[1];
15427 var contentCfg = cfg.cn[2];
15430 if(this.indicatorpos == 'right'){
15435 cls : 'control-label col-form-label',
15439 html : this.fieldLabel
15443 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15444 tooltip : 'This field is required'
15457 labelCfg = cfg.cn[0];
15458 contentCfg = cfg.cn[1];
15463 if(this.labelWidth > 12){
15464 labelCfg.style = "width: " + this.labelWidth + 'px';
15467 if(this.labelWidth < 13 && this.labelmd == 0){
15468 this.labelmd = this.labelWidth;
15471 if(this.labellg > 0){
15472 labelCfg.cls += ' col-lg-' + this.labellg;
15473 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15476 if(this.labelmd > 0){
15477 labelCfg.cls += ' col-md-' + this.labelmd;
15478 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15481 if(this.labelsm > 0){
15482 labelCfg.cls += ' col-sm-' + this.labelsm;
15483 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15486 if(this.labelxs > 0){
15487 labelCfg.cls += ' col-xs-' + this.labelxs;
15488 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15492 } else if ( this.fieldLabel.length) {
15496 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15497 tooltip : 'This field is required'
15501 cls : 'control-label',
15502 html : this.fieldLabel
15513 if(this.indicatorpos == 'right'){
15517 cls : 'control-label',
15518 html : this.fieldLabel,
15522 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15523 tooltip : 'This field is required'
15540 var settings = this;
15542 ['xs','sm','md','lg'].map(function(size){
15543 if (settings[size]) {
15544 cfg.cls += ' col-' + size + '-' + settings[size];
15551 initTouchView : function()
15553 this.renderTouchView();
15555 this.touchViewEl.on('scroll', function(){
15556 this.el.dom.scrollTop = 0;
15559 this.originalValue = this.getValue();
15561 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15563 this.inputEl().on("click", this.showTouchView, this);
15564 if (this.triggerEl) {
15565 this.triggerEl.on("click", this.showTouchView, this);
15569 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15570 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15572 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15574 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15575 this.store.on('load', this.onTouchViewLoad, this);
15576 this.store.on('loadexception', this.onTouchViewLoadException, this);
15578 if(this.hiddenName){
15580 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15582 this.hiddenField.dom.value =
15583 this.hiddenValue !== undefined ? this.hiddenValue :
15584 this.value !== undefined ? this.value : '';
15586 this.el.dom.removeAttribute('name');
15587 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15591 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15592 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15595 if(this.removable && !this.multiple){
15596 var close = this.closeTriggerEl();
15598 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15599 close.on('click', this.removeBtnClick, this, close);
15603 * fix the bug in Safari iOS8
15605 this.inputEl().on("focus", function(e){
15606 document.activeElement.blur();
15609 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15616 renderTouchView : function()
15618 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15619 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15621 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15622 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15624 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15625 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15626 this.touchViewBodyEl.setStyle('overflow', 'auto');
15628 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15629 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15631 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15632 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15636 showTouchView : function()
15642 this.touchViewHeaderEl.hide();
15644 if(this.modalTitle.length){
15645 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15646 this.touchViewHeaderEl.show();
15649 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15650 this.touchViewEl.show();
15652 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15654 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15655 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15657 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15659 if(this.modalTitle.length){
15660 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15663 this.touchViewBodyEl.setHeight(bodyHeight);
15667 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15669 this.touchViewEl.addClass('in');
15672 if(this._touchViewMask){
15673 Roo.get(document.body).addClass("x-body-masked");
15674 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15675 this._touchViewMask.setStyle('z-index', 10000);
15676 this._touchViewMask.addClass('show');
15679 this.doTouchViewQuery();
15683 hideTouchView : function()
15685 this.touchViewEl.removeClass('in');
15689 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15691 this.touchViewEl.setStyle('display', 'none');
15694 if(this._touchViewMask){
15695 this._touchViewMask.removeClass('show');
15696 Roo.get(document.body).removeClass("x-body-masked");
15700 setTouchViewValue : function()
15707 Roo.each(this.tickItems, function(o){
15712 this.hideTouchView();
15715 doTouchViewQuery : function()
15724 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15728 if(!this.alwaysQuery || this.mode == 'local'){
15729 this.onTouchViewLoad();
15736 onTouchViewBeforeLoad : function(combo,opts)
15742 onTouchViewLoad : function()
15744 if(this.store.getCount() < 1){
15745 this.onTouchViewEmptyResults();
15749 this.clearTouchView();
15751 var rawValue = this.getRawValue();
15753 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15755 this.tickItems = [];
15757 this.store.data.each(function(d, rowIndex){
15758 var row = this.touchViewListGroup.createChild(template);
15760 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15761 row.addClass(d.data.cls);
15764 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15767 html : d.data[this.displayField]
15770 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15771 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15774 row.removeClass('selected');
15775 if(!this.multiple && this.valueField &&
15776 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15779 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15780 row.addClass('selected');
15783 if(this.multiple && this.valueField &&
15784 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15788 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15789 this.tickItems.push(d.data);
15792 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15796 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15798 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15800 if(this.modalTitle.length){
15801 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15804 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15806 if(this.mobile_restrict_height && listHeight < bodyHeight){
15807 this.touchViewBodyEl.setHeight(listHeight);
15812 if(firstChecked && listHeight > bodyHeight){
15813 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15818 onTouchViewLoadException : function()
15820 this.hideTouchView();
15823 onTouchViewEmptyResults : function()
15825 this.clearTouchView();
15827 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15829 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15833 clearTouchView : function()
15835 this.touchViewListGroup.dom.innerHTML = '';
15838 onTouchViewClick : function(e, el, o)
15840 e.preventDefault();
15843 var rowIndex = o.rowIndex;
15845 var r = this.store.getAt(rowIndex);
15847 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15849 if(!this.multiple){
15850 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15851 c.dom.removeAttribute('checked');
15854 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15856 this.setFromData(r.data);
15858 var close = this.closeTriggerEl();
15864 this.hideTouchView();
15866 this.fireEvent('select', this, r, rowIndex);
15871 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15872 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15873 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15877 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15878 this.addItem(r.data);
15879 this.tickItems.push(r.data);
15883 getAutoCreateNativeIOS : function()
15886 cls: 'form-group' //input-group,
15891 cls : 'roo-ios-select'
15895 combobox.name = this.name;
15898 if (this.disabled) {
15899 combobox.disabled = true;
15902 var settings = this;
15904 ['xs','sm','md','lg'].map(function(size){
15905 if (settings[size]) {
15906 cfg.cls += ' col-' + size + '-' + settings[size];
15916 initIOSView : function()
15918 this.store.on('load', this.onIOSViewLoad, this);
15923 onIOSViewLoad : function()
15925 if(this.store.getCount() < 1){
15929 this.clearIOSView();
15931 if(this.allowBlank) {
15933 var default_text = '-- SELECT --';
15935 if(this.placeholder.length){
15936 default_text = this.placeholder;
15939 if(this.emptyTitle.length){
15940 default_text += ' - ' + this.emptyTitle + ' -';
15943 var opt = this.inputEl().createChild({
15946 html : default_text
15950 o[this.valueField] = 0;
15951 o[this.displayField] = default_text;
15953 this.ios_options.push({
15960 this.store.data.each(function(d, rowIndex){
15964 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15965 html = d.data[this.displayField];
15970 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15971 value = d.data[this.valueField];
15980 if(this.value == d.data[this.valueField]){
15981 option['selected'] = true;
15984 var opt = this.inputEl().createChild(option);
15986 this.ios_options.push({
15993 this.inputEl().on('change', function(){
15994 this.fireEvent('select', this);
15999 clearIOSView: function()
16001 this.inputEl().dom.innerHTML = '';
16003 this.ios_options = [];
16006 setIOSValue: function(v)
16010 if(!this.ios_options){
16014 Roo.each(this.ios_options, function(opts){
16016 opts.el.dom.removeAttribute('selected');
16018 if(opts.data[this.valueField] != v){
16022 opts.el.dom.setAttribute('selected', true);
16028 * @cfg {Boolean} grow
16032 * @cfg {Number} growMin
16036 * @cfg {Number} growMax
16045 Roo.apply(Roo.bootstrap.ComboBox, {
16049 cls: 'modal-header',
16071 cls: 'list-group-item',
16075 cls: 'roo-combobox-list-group-item-value'
16079 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16093 listItemCheckbox : {
16095 cls: 'list-group-item',
16099 cls: 'roo-combobox-list-group-item-value'
16103 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16119 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16124 cls: 'modal-footer',
16132 cls: 'col-xs-6 text-left',
16135 cls: 'btn btn-danger roo-touch-view-cancel',
16141 cls: 'col-xs-6 text-right',
16144 cls: 'btn btn-success roo-touch-view-ok',
16155 Roo.apply(Roo.bootstrap.ComboBox, {
16157 touchViewTemplate : {
16159 cls: 'modal fade roo-combobox-touch-view',
16163 cls: 'modal-dialog',
16164 style : 'position:fixed', // we have to fix position....
16168 cls: 'modal-content',
16170 Roo.bootstrap.ComboBox.header,
16171 Roo.bootstrap.ComboBox.body,
16172 Roo.bootstrap.ComboBox.footer
16181 * Ext JS Library 1.1.1
16182 * Copyright(c) 2006-2007, Ext JS, LLC.
16184 * Originally Released Under LGPL - original licence link has changed is not relivant.
16187 * <script type="text/javascript">
16192 * @extends Roo.util.Observable
16193 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16194 * This class also supports single and multi selection modes. <br>
16195 * Create a data model bound view:
16197 var store = new Roo.data.Store(...);
16199 var view = new Roo.View({
16201 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16203 singleSelect: true,
16204 selectedClass: "ydataview-selected",
16208 // listen for node click?
16209 view.on("click", function(vw, index, node, e){
16210 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16214 dataModel.load("foobar.xml");
16216 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16218 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16219 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16221 * Note: old style constructor is still suported (container, template, config)
16224 * Create a new View
16225 * @param {Object} config The config object
16228 Roo.View = function(config, depreciated_tpl, depreciated_config){
16230 this.parent = false;
16232 if (typeof(depreciated_tpl) == 'undefined') {
16233 // new way.. - universal constructor.
16234 Roo.apply(this, config);
16235 this.el = Roo.get(this.el);
16238 this.el = Roo.get(config);
16239 this.tpl = depreciated_tpl;
16240 Roo.apply(this, depreciated_config);
16242 this.wrapEl = this.el.wrap().wrap();
16243 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16246 if(typeof(this.tpl) == "string"){
16247 this.tpl = new Roo.Template(this.tpl);
16249 // support xtype ctors..
16250 this.tpl = new Roo.factory(this.tpl, Roo);
16254 this.tpl.compile();
16259 * @event beforeclick
16260 * Fires before a click is processed. Returns false to cancel the default action.
16261 * @param {Roo.View} this
16262 * @param {Number} index The index of the target node
16263 * @param {HTMLElement} node The target node
16264 * @param {Roo.EventObject} e The raw event object
16266 "beforeclick" : true,
16269 * Fires when a template node is clicked.
16270 * @param {Roo.View} this
16271 * @param {Number} index The index of the target node
16272 * @param {HTMLElement} node The target node
16273 * @param {Roo.EventObject} e The raw event object
16278 * Fires when a template node is double clicked.
16279 * @param {Roo.View} this
16280 * @param {Number} index The index of the target node
16281 * @param {HTMLElement} node The target node
16282 * @param {Roo.EventObject} e The raw event object
16286 * @event contextmenu
16287 * Fires when a template node is right clicked.
16288 * @param {Roo.View} this
16289 * @param {Number} index The index of the target node
16290 * @param {HTMLElement} node The target node
16291 * @param {Roo.EventObject} e The raw event object
16293 "contextmenu" : true,
16295 * @event selectionchange
16296 * Fires when the selected nodes change.
16297 * @param {Roo.View} this
16298 * @param {Array} selections Array of the selected nodes
16300 "selectionchange" : true,
16303 * @event beforeselect
16304 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16305 * @param {Roo.View} this
16306 * @param {HTMLElement} node The node to be selected
16307 * @param {Array} selections Array of currently selected nodes
16309 "beforeselect" : true,
16311 * @event preparedata
16312 * Fires on every row to render, to allow you to change the data.
16313 * @param {Roo.View} this
16314 * @param {Object} data to be rendered (change this)
16316 "preparedata" : true
16324 "click": this.onClick,
16325 "dblclick": this.onDblClick,
16326 "contextmenu": this.onContextMenu,
16330 this.selections = [];
16332 this.cmp = new Roo.CompositeElementLite([]);
16334 this.store = Roo.factory(this.store, Roo.data);
16335 this.setStore(this.store, true);
16338 if ( this.footer && this.footer.xtype) {
16340 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16342 this.footer.dataSource = this.store;
16343 this.footer.container = fctr;
16344 this.footer = Roo.factory(this.footer, Roo);
16345 fctr.insertFirst(this.el);
16347 // this is a bit insane - as the paging toolbar seems to detach the el..
16348 // dom.parentNode.parentNode.parentNode
16349 // they get detached?
16353 Roo.View.superclass.constructor.call(this);
16358 Roo.extend(Roo.View, Roo.util.Observable, {
16361 * @cfg {Roo.data.Store} store Data store to load data from.
16366 * @cfg {String|Roo.Element} el The container element.
16371 * @cfg {String|Roo.Template} tpl The template used by this View
16375 * @cfg {String} dataName the named area of the template to use as the data area
16376 * Works with domtemplates roo-name="name"
16380 * @cfg {String} selectedClass The css class to add to selected nodes
16382 selectedClass : "x-view-selected",
16384 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16389 * @cfg {String} text to display on mask (default Loading)
16393 * @cfg {Boolean} multiSelect Allow multiple selection
16395 multiSelect : false,
16397 * @cfg {Boolean} singleSelect Allow single selection
16399 singleSelect: false,
16402 * @cfg {Boolean} toggleSelect - selecting
16404 toggleSelect : false,
16407 * @cfg {Boolean} tickable - selecting
16412 * Returns the element this view is bound to.
16413 * @return {Roo.Element}
16415 getEl : function(){
16416 return this.wrapEl;
16422 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16424 refresh : function(){
16425 //Roo.log('refresh');
16428 // if we are using something like 'domtemplate', then
16429 // the what gets used is:
16430 // t.applySubtemplate(NAME, data, wrapping data..)
16431 // the outer template then get' applied with
16432 // the store 'extra data'
16433 // and the body get's added to the
16434 // roo-name="data" node?
16435 // <span class='roo-tpl-{name}'></span> ?????
16439 this.clearSelections();
16440 this.el.update("");
16442 var records = this.store.getRange();
16443 if(records.length < 1) {
16445 // is this valid?? = should it render a template??
16447 this.el.update(this.emptyText);
16451 if (this.dataName) {
16452 this.el.update(t.apply(this.store.meta)); //????
16453 el = this.el.child('.roo-tpl-' + this.dataName);
16456 for(var i = 0, len = records.length; i < len; i++){
16457 var data = this.prepareData(records[i].data, i, records[i]);
16458 this.fireEvent("preparedata", this, data, i, records[i]);
16460 var d = Roo.apply({}, data);
16463 Roo.apply(d, {'roo-id' : Roo.id()});
16467 Roo.each(this.parent.item, function(item){
16468 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16471 Roo.apply(d, {'roo-data-checked' : 'checked'});
16475 html[html.length] = Roo.util.Format.trim(
16477 t.applySubtemplate(this.dataName, d, this.store.meta) :
16484 el.update(html.join(""));
16485 this.nodes = el.dom.childNodes;
16486 this.updateIndexes(0);
16491 * Function to override to reformat the data that is sent to
16492 * the template for each node.
16493 * DEPRICATED - use the preparedata event handler.
16494 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16495 * a JSON object for an UpdateManager bound view).
16497 prepareData : function(data, index, record)
16499 this.fireEvent("preparedata", this, data, index, record);
16503 onUpdate : function(ds, record){
16504 // Roo.log('on update');
16505 this.clearSelections();
16506 var index = this.store.indexOf(record);
16507 var n = this.nodes[index];
16508 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16509 n.parentNode.removeChild(n);
16510 this.updateIndexes(index, index);
16516 onAdd : function(ds, records, index)
16518 //Roo.log(['on Add', ds, records, index] );
16519 this.clearSelections();
16520 if(this.nodes.length == 0){
16524 var n = this.nodes[index];
16525 for(var i = 0, len = records.length; i < len; i++){
16526 var d = this.prepareData(records[i].data, i, records[i]);
16528 this.tpl.insertBefore(n, d);
16531 this.tpl.append(this.el, d);
16534 this.updateIndexes(index);
16537 onRemove : function(ds, record, index){
16538 // Roo.log('onRemove');
16539 this.clearSelections();
16540 var el = this.dataName ?
16541 this.el.child('.roo-tpl-' + this.dataName) :
16544 el.dom.removeChild(this.nodes[index]);
16545 this.updateIndexes(index);
16549 * Refresh an individual node.
16550 * @param {Number} index
16552 refreshNode : function(index){
16553 this.onUpdate(this.store, this.store.getAt(index));
16556 updateIndexes : function(startIndex, endIndex){
16557 var ns = this.nodes;
16558 startIndex = startIndex || 0;
16559 endIndex = endIndex || ns.length - 1;
16560 for(var i = startIndex; i <= endIndex; i++){
16561 ns[i].nodeIndex = i;
16566 * Changes the data store this view uses and refresh the view.
16567 * @param {Store} store
16569 setStore : function(store, initial){
16570 if(!initial && this.store){
16571 this.store.un("datachanged", this.refresh);
16572 this.store.un("add", this.onAdd);
16573 this.store.un("remove", this.onRemove);
16574 this.store.un("update", this.onUpdate);
16575 this.store.un("clear", this.refresh);
16576 this.store.un("beforeload", this.onBeforeLoad);
16577 this.store.un("load", this.onLoad);
16578 this.store.un("loadexception", this.onLoad);
16582 store.on("datachanged", this.refresh, this);
16583 store.on("add", this.onAdd, this);
16584 store.on("remove", this.onRemove, this);
16585 store.on("update", this.onUpdate, this);
16586 store.on("clear", this.refresh, this);
16587 store.on("beforeload", this.onBeforeLoad, this);
16588 store.on("load", this.onLoad, this);
16589 store.on("loadexception", this.onLoad, this);
16597 * onbeforeLoad - masks the loading area.
16600 onBeforeLoad : function(store,opts)
16602 //Roo.log('onBeforeLoad');
16604 this.el.update("");
16606 this.el.mask(this.mask ? this.mask : "Loading" );
16608 onLoad : function ()
16615 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16616 * @param {HTMLElement} node
16617 * @return {HTMLElement} The template node
16619 findItemFromChild : function(node){
16620 var el = this.dataName ?
16621 this.el.child('.roo-tpl-' + this.dataName,true) :
16624 if(!node || node.parentNode == el){
16627 var p = node.parentNode;
16628 while(p && p != el){
16629 if(p.parentNode == el){
16638 onClick : function(e){
16639 var item = this.findItemFromChild(e.getTarget());
16641 var index = this.indexOf(item);
16642 if(this.onItemClick(item, index, e) !== false){
16643 this.fireEvent("click", this, index, item, e);
16646 this.clearSelections();
16651 onContextMenu : function(e){
16652 var item = this.findItemFromChild(e.getTarget());
16654 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16659 onDblClick : function(e){
16660 var item = this.findItemFromChild(e.getTarget());
16662 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16666 onItemClick : function(item, index, e)
16668 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16671 if (this.toggleSelect) {
16672 var m = this.isSelected(item) ? 'unselect' : 'select';
16675 _t[m](item, true, false);
16678 if(this.multiSelect || this.singleSelect){
16679 if(this.multiSelect && e.shiftKey && this.lastSelection){
16680 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16682 this.select(item, this.multiSelect && e.ctrlKey);
16683 this.lastSelection = item;
16686 if(!this.tickable){
16687 e.preventDefault();
16695 * Get the number of selected nodes.
16698 getSelectionCount : function(){
16699 return this.selections.length;
16703 * Get the currently selected nodes.
16704 * @return {Array} An array of HTMLElements
16706 getSelectedNodes : function(){
16707 return this.selections;
16711 * Get the indexes of the selected nodes.
16714 getSelectedIndexes : function(){
16715 var indexes = [], s = this.selections;
16716 for(var i = 0, len = s.length; i < len; i++){
16717 indexes.push(s[i].nodeIndex);
16723 * Clear all selections
16724 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16726 clearSelections : function(suppressEvent){
16727 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16728 this.cmp.elements = this.selections;
16729 this.cmp.removeClass(this.selectedClass);
16730 this.selections = [];
16731 if(!suppressEvent){
16732 this.fireEvent("selectionchange", this, this.selections);
16738 * Returns true if the passed node is selected
16739 * @param {HTMLElement/Number} node The node or node index
16740 * @return {Boolean}
16742 isSelected : function(node){
16743 var s = this.selections;
16747 node = this.getNode(node);
16748 return s.indexOf(node) !== -1;
16753 * @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
16754 * @param {Boolean} keepExisting (optional) true to keep existing selections
16755 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16757 select : function(nodeInfo, keepExisting, suppressEvent){
16758 if(nodeInfo instanceof Array){
16760 this.clearSelections(true);
16762 for(var i = 0, len = nodeInfo.length; i < len; i++){
16763 this.select(nodeInfo[i], true, true);
16767 var node = this.getNode(nodeInfo);
16768 if(!node || this.isSelected(node)){
16769 return; // already selected.
16772 this.clearSelections(true);
16775 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16776 Roo.fly(node).addClass(this.selectedClass);
16777 this.selections.push(node);
16778 if(!suppressEvent){
16779 this.fireEvent("selectionchange", this, this.selections);
16787 * @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
16788 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16789 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16791 unselect : function(nodeInfo, keepExisting, suppressEvent)
16793 if(nodeInfo instanceof Array){
16794 Roo.each(this.selections, function(s) {
16795 this.unselect(s, nodeInfo);
16799 var node = this.getNode(nodeInfo);
16800 if(!node || !this.isSelected(node)){
16801 //Roo.log("not selected");
16802 return; // not selected.
16806 Roo.each(this.selections, function(s) {
16808 Roo.fly(node).removeClass(this.selectedClass);
16815 this.selections= ns;
16816 this.fireEvent("selectionchange", this, this.selections);
16820 * Gets a template node.
16821 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16822 * @return {HTMLElement} The node or null if it wasn't found
16824 getNode : function(nodeInfo){
16825 if(typeof nodeInfo == "string"){
16826 return document.getElementById(nodeInfo);
16827 }else if(typeof nodeInfo == "number"){
16828 return this.nodes[nodeInfo];
16834 * Gets a range template nodes.
16835 * @param {Number} startIndex
16836 * @param {Number} endIndex
16837 * @return {Array} An array of nodes
16839 getNodes : function(start, end){
16840 var ns = this.nodes;
16841 start = start || 0;
16842 end = typeof end == "undefined" ? ns.length - 1 : end;
16845 for(var i = start; i <= end; i++){
16849 for(var i = start; i >= end; i--){
16857 * Finds the index of the passed node
16858 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16859 * @return {Number} The index of the node or -1
16861 indexOf : function(node){
16862 node = this.getNode(node);
16863 if(typeof node.nodeIndex == "number"){
16864 return node.nodeIndex;
16866 var ns = this.nodes;
16867 for(var i = 0, len = ns.length; i < len; i++){
16878 * based on jquery fullcalendar
16882 Roo.bootstrap = Roo.bootstrap || {};
16884 * @class Roo.bootstrap.Calendar
16885 * @extends Roo.bootstrap.Component
16886 * Bootstrap Calendar class
16887 * @cfg {Boolean} loadMask (true|false) default false
16888 * @cfg {Object} header generate the user specific header of the calendar, default false
16891 * Create a new Container
16892 * @param {Object} config The config object
16897 Roo.bootstrap.Calendar = function(config){
16898 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16902 * Fires when a date is selected
16903 * @param {DatePicker} this
16904 * @param {Date} date The selected date
16908 * @event monthchange
16909 * Fires when the displayed month changes
16910 * @param {DatePicker} this
16911 * @param {Date} date The selected month
16913 'monthchange': true,
16915 * @event evententer
16916 * Fires when mouse over an event
16917 * @param {Calendar} this
16918 * @param {event} Event
16920 'evententer': true,
16922 * @event eventleave
16923 * Fires when the mouse leaves an
16924 * @param {Calendar} this
16927 'eventleave': true,
16929 * @event eventclick
16930 * Fires when the mouse click an
16931 * @param {Calendar} this
16940 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16943 * @cfg {Number} startDay
16944 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16952 getAutoCreate : function(){
16955 var fc_button = function(name, corner, style, content ) {
16956 return Roo.apply({},{
16958 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16960 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16963 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16974 style : 'width:100%',
16981 cls : 'fc-header-left',
16983 fc_button('prev', 'left', 'arrow', '‹' ),
16984 fc_button('next', 'right', 'arrow', '›' ),
16985 { tag: 'span', cls: 'fc-header-space' },
16986 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16994 cls : 'fc-header-center',
16998 cls: 'fc-header-title',
17001 html : 'month / year'
17009 cls : 'fc-header-right',
17011 /* fc_button('month', 'left', '', 'month' ),
17012 fc_button('week', '', '', 'week' ),
17013 fc_button('day', 'right', '', 'day' )
17025 header = this.header;
17028 var cal_heads = function() {
17030 // fixme - handle this.
17032 for (var i =0; i < Date.dayNames.length; i++) {
17033 var d = Date.dayNames[i];
17036 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
17037 html : d.substring(0,3)
17041 ret[0].cls += ' fc-first';
17042 ret[6].cls += ' fc-last';
17045 var cal_cell = function(n) {
17048 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17053 cls: 'fc-day-number',
17057 cls: 'fc-day-content',
17061 style: 'position: relative;' // height: 17px;
17073 var cal_rows = function() {
17076 for (var r = 0; r < 6; r++) {
17083 for (var i =0; i < Date.dayNames.length; i++) {
17084 var d = Date.dayNames[i];
17085 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17088 row.cn[0].cls+=' fc-first';
17089 row.cn[0].cn[0].style = 'min-height:90px';
17090 row.cn[6].cls+=' fc-last';
17094 ret[0].cls += ' fc-first';
17095 ret[4].cls += ' fc-prev-last';
17096 ret[5].cls += ' fc-last';
17103 cls: 'fc-border-separate',
17104 style : 'width:100%',
17112 cls : 'fc-first fc-last',
17130 cls : 'fc-content',
17131 style : "position: relative;",
17134 cls : 'fc-view fc-view-month fc-grid',
17135 style : 'position: relative',
17136 unselectable : 'on',
17139 cls : 'fc-event-container',
17140 style : 'position:absolute;z-index:8;top:0;left:0;'
17158 initEvents : function()
17161 throw "can not find store for calendar";
17167 style: "text-align:center",
17171 style: "background-color:white;width:50%;margin:250 auto",
17175 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17186 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17188 var size = this.el.select('.fc-content', true).first().getSize();
17189 this.maskEl.setSize(size.width, size.height);
17190 this.maskEl.enableDisplayMode("block");
17191 if(!this.loadMask){
17192 this.maskEl.hide();
17195 this.store = Roo.factory(this.store, Roo.data);
17196 this.store.on('load', this.onLoad, this);
17197 this.store.on('beforeload', this.onBeforeLoad, this);
17201 this.cells = this.el.select('.fc-day',true);
17202 //Roo.log(this.cells);
17203 this.textNodes = this.el.query('.fc-day-number');
17204 this.cells.addClassOnOver('fc-state-hover');
17206 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17207 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17208 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17209 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17211 this.on('monthchange', this.onMonthChange, this);
17213 this.update(new Date().clearTime());
17216 resize : function() {
17217 var sz = this.el.getSize();
17219 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17220 this.el.select('.fc-day-content div',true).setHeight(34);
17225 showPrevMonth : function(e){
17226 this.update(this.activeDate.add("mo", -1));
17228 showToday : function(e){
17229 this.update(new Date().clearTime());
17232 showNextMonth : function(e){
17233 this.update(this.activeDate.add("mo", 1));
17237 showPrevYear : function(){
17238 this.update(this.activeDate.add("y", -1));
17242 showNextYear : function(){
17243 this.update(this.activeDate.add("y", 1));
17248 update : function(date)
17250 var vd = this.activeDate;
17251 this.activeDate = date;
17252 // if(vd && this.el){
17253 // var t = date.getTime();
17254 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17255 // Roo.log('using add remove');
17257 // this.fireEvent('monthchange', this, date);
17259 // this.cells.removeClass("fc-state-highlight");
17260 // this.cells.each(function(c){
17261 // if(c.dateValue == t){
17262 // c.addClass("fc-state-highlight");
17263 // setTimeout(function(){
17264 // try{c.dom.firstChild.focus();}catch(e){}
17274 var days = date.getDaysInMonth();
17276 var firstOfMonth = date.getFirstDateOfMonth();
17277 var startingPos = firstOfMonth.getDay()-this.startDay;
17279 if(startingPos < this.startDay){
17283 var pm = date.add(Date.MONTH, -1);
17284 var prevStart = pm.getDaysInMonth()-startingPos;
17286 this.cells = this.el.select('.fc-day',true);
17287 this.textNodes = this.el.query('.fc-day-number');
17288 this.cells.addClassOnOver('fc-state-hover');
17290 var cells = this.cells.elements;
17291 var textEls = this.textNodes;
17293 Roo.each(cells, function(cell){
17294 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17297 days += startingPos;
17299 // convert everything to numbers so it's fast
17300 var day = 86400000;
17301 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17304 //Roo.log(prevStart);
17306 var today = new Date().clearTime().getTime();
17307 var sel = date.clearTime().getTime();
17308 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17309 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17310 var ddMatch = this.disabledDatesRE;
17311 var ddText = this.disabledDatesText;
17312 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17313 var ddaysText = this.disabledDaysText;
17314 var format = this.format;
17316 var setCellClass = function(cal, cell){
17320 //Roo.log('set Cell Class');
17322 var t = d.getTime();
17326 cell.dateValue = t;
17328 cell.className += " fc-today";
17329 cell.className += " fc-state-highlight";
17330 cell.title = cal.todayText;
17333 // disable highlight in other month..
17334 //cell.className += " fc-state-highlight";
17339 cell.className = " fc-state-disabled";
17340 cell.title = cal.minText;
17344 cell.className = " fc-state-disabled";
17345 cell.title = cal.maxText;
17349 if(ddays.indexOf(d.getDay()) != -1){
17350 cell.title = ddaysText;
17351 cell.className = " fc-state-disabled";
17354 if(ddMatch && format){
17355 var fvalue = d.dateFormat(format);
17356 if(ddMatch.test(fvalue)){
17357 cell.title = ddText.replace("%0", fvalue);
17358 cell.className = " fc-state-disabled";
17362 if (!cell.initialClassName) {
17363 cell.initialClassName = cell.dom.className;
17366 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17371 for(; i < startingPos; i++) {
17372 textEls[i].innerHTML = (++prevStart);
17373 d.setDate(d.getDate()+1);
17375 cells[i].className = "fc-past fc-other-month";
17376 setCellClass(this, cells[i]);
17381 for(; i < days; i++){
17382 intDay = i - startingPos + 1;
17383 textEls[i].innerHTML = (intDay);
17384 d.setDate(d.getDate()+1);
17386 cells[i].className = ''; // "x-date-active";
17387 setCellClass(this, cells[i]);
17391 for(; i < 42; i++) {
17392 textEls[i].innerHTML = (++extraDays);
17393 d.setDate(d.getDate()+1);
17395 cells[i].className = "fc-future fc-other-month";
17396 setCellClass(this, cells[i]);
17399 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17401 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17403 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17404 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17406 if(totalRows != 6){
17407 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17408 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17411 this.fireEvent('monthchange', this, date);
17415 if(!this.internalRender){
17416 var main = this.el.dom.firstChild;
17417 var w = main.offsetWidth;
17418 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17419 Roo.fly(main).setWidth(w);
17420 this.internalRender = true;
17421 // opera does not respect the auto grow header center column
17422 // then, after it gets a width opera refuses to recalculate
17423 // without a second pass
17424 if(Roo.isOpera && !this.secondPass){
17425 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17426 this.secondPass = true;
17427 this.update.defer(10, this, [date]);
17434 findCell : function(dt) {
17435 dt = dt.clearTime().getTime();
17437 this.cells.each(function(c){
17438 //Roo.log("check " +c.dateValue + '?=' + dt);
17439 if(c.dateValue == dt){
17449 findCells : function(ev) {
17450 var s = ev.start.clone().clearTime().getTime();
17452 var e= ev.end.clone().clearTime().getTime();
17455 this.cells.each(function(c){
17456 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17458 if(c.dateValue > e){
17461 if(c.dateValue < s){
17470 // findBestRow: function(cells)
17474 // for (var i =0 ; i < cells.length;i++) {
17475 // ret = Math.max(cells[i].rows || 0,ret);
17482 addItem : function(ev)
17484 // look for vertical location slot in
17485 var cells = this.findCells(ev);
17487 // ev.row = this.findBestRow(cells);
17489 // work out the location.
17493 for(var i =0; i < cells.length; i++) {
17495 cells[i].row = cells[0].row;
17498 cells[i].row = cells[i].row + 1;
17508 if (crow.start.getY() == cells[i].getY()) {
17510 crow.end = cells[i];
17527 cells[0].events.push(ev);
17529 this.calevents.push(ev);
17532 clearEvents: function() {
17534 if(!this.calevents){
17538 Roo.each(this.cells.elements, function(c){
17544 Roo.each(this.calevents, function(e) {
17545 Roo.each(e.els, function(el) {
17546 el.un('mouseenter' ,this.onEventEnter, this);
17547 el.un('mouseleave' ,this.onEventLeave, this);
17552 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17558 renderEvents: function()
17562 this.cells.each(function(c) {
17571 if(c.row != c.events.length){
17572 r = 4 - (4 - (c.row - c.events.length));
17575 c.events = ev.slice(0, r);
17576 c.more = ev.slice(r);
17578 if(c.more.length && c.more.length == 1){
17579 c.events.push(c.more.pop());
17582 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17586 this.cells.each(function(c) {
17588 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17591 for (var e = 0; e < c.events.length; e++){
17592 var ev = c.events[e];
17593 var rows = ev.rows;
17595 for(var i = 0; i < rows.length; i++) {
17597 // how many rows should it span..
17600 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17601 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17603 unselectable : "on",
17606 cls: 'fc-event-inner',
17610 // cls: 'fc-event-time',
17611 // html : cells.length > 1 ? '' : ev.time
17615 cls: 'fc-event-title',
17616 html : String.format('{0}', ev.title)
17623 cls: 'ui-resizable-handle ui-resizable-e',
17624 html : '  '
17631 cfg.cls += ' fc-event-start';
17633 if ((i+1) == rows.length) {
17634 cfg.cls += ' fc-event-end';
17637 var ctr = _this.el.select('.fc-event-container',true).first();
17638 var cg = ctr.createChild(cfg);
17640 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17641 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17643 var r = (c.more.length) ? 1 : 0;
17644 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17645 cg.setWidth(ebox.right - sbox.x -2);
17647 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17648 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17649 cg.on('click', _this.onEventClick, _this, ev);
17660 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17661 style : 'position: absolute',
17662 unselectable : "on",
17665 cls: 'fc-event-inner',
17669 cls: 'fc-event-title',
17677 cls: 'ui-resizable-handle ui-resizable-e',
17678 html : '  '
17684 var ctr = _this.el.select('.fc-event-container',true).first();
17685 var cg = ctr.createChild(cfg);
17687 var sbox = c.select('.fc-day-content',true).first().getBox();
17688 var ebox = c.select('.fc-day-content',true).first().getBox();
17690 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17691 cg.setWidth(ebox.right - sbox.x -2);
17693 cg.on('click', _this.onMoreEventClick, _this, c.more);
17703 onEventEnter: function (e, el,event,d) {
17704 this.fireEvent('evententer', this, el, event);
17707 onEventLeave: function (e, el,event,d) {
17708 this.fireEvent('eventleave', this, el, event);
17711 onEventClick: function (e, el,event,d) {
17712 this.fireEvent('eventclick', this, el, event);
17715 onMonthChange: function () {
17719 onMoreEventClick: function(e, el, more)
17723 this.calpopover.placement = 'right';
17724 this.calpopover.setTitle('More');
17726 this.calpopover.setContent('');
17728 var ctr = this.calpopover.el.select('.popover-content', true).first();
17730 Roo.each(more, function(m){
17732 cls : 'fc-event-hori fc-event-draggable',
17735 var cg = ctr.createChild(cfg);
17737 cg.on('click', _this.onEventClick, _this, m);
17740 this.calpopover.show(el);
17745 onLoad: function ()
17747 this.calevents = [];
17750 if(this.store.getCount() > 0){
17751 this.store.data.each(function(d){
17754 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17755 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17756 time : d.data.start_time,
17757 title : d.data.title,
17758 description : d.data.description,
17759 venue : d.data.venue
17764 this.renderEvents();
17766 if(this.calevents.length && this.loadMask){
17767 this.maskEl.hide();
17771 onBeforeLoad: function()
17773 this.clearEvents();
17775 this.maskEl.show();
17789 * @class Roo.bootstrap.Popover
17790 * @extends Roo.bootstrap.Component
17791 * Bootstrap Popover class
17792 * @cfg {String} html contents of the popover (or false to use children..)
17793 * @cfg {String} title of popover (or false to hide)
17794 * @cfg {String} placement how it is placed
17795 * @cfg {String} trigger click || hover (or false to trigger manually)
17796 * @cfg {String} over what (parent or false to trigger manually.)
17797 * @cfg {Number} delay - delay before showing
17800 * Create a new Popover
17801 * @param {Object} config The config object
17804 Roo.bootstrap.Popover = function(config){
17805 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17811 * After the popover show
17813 * @param {Roo.bootstrap.Popover} this
17818 * After the popover hide
17820 * @param {Roo.bootstrap.Popover} this
17826 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17828 title: 'Fill in a title',
17831 placement : 'right',
17832 trigger : 'hover', // hover
17838 can_build_overlaid : false,
17840 getChildContainer : function()
17842 return this.el.select('.popover-content',true).first();
17845 getAutoCreate : function(){
17848 cls : 'popover roo-dynamic',
17849 style: 'display:block',
17855 cls : 'popover-inner',
17859 cls: 'popover-title popover-header',
17863 cls : 'popover-content popover-body',
17874 setTitle: function(str)
17877 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17879 setContent: function(str)
17882 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17884 // as it get's added to the bottom of the page.
17885 onRender : function(ct, position)
17887 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17889 var cfg = Roo.apply({}, this.getAutoCreate());
17893 cfg.cls += ' ' + this.cls;
17896 cfg.style = this.style;
17898 //Roo.log("adding to ");
17899 this.el = Roo.get(document.body).createChild(cfg, position);
17900 // Roo.log(this.el);
17905 initEvents : function()
17907 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17908 this.el.enableDisplayMode('block');
17910 if (this.over === false) {
17913 if (this.triggers === false) {
17916 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17917 var triggers = this.trigger ? this.trigger.split(' ') : [];
17918 Roo.each(triggers, function(trigger) {
17920 if (trigger == 'click') {
17921 on_el.on('click', this.toggle, this);
17922 } else if (trigger != 'manual') {
17923 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17924 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17926 on_el.on(eventIn ,this.enter, this);
17927 on_el.on(eventOut, this.leave, this);
17938 toggle : function () {
17939 this.hoverState == 'in' ? this.leave() : this.enter();
17942 enter : function () {
17944 clearTimeout(this.timeout);
17946 this.hoverState = 'in';
17948 if (!this.delay || !this.delay.show) {
17953 this.timeout = setTimeout(function () {
17954 if (_t.hoverState == 'in') {
17957 }, this.delay.show)
17960 leave : function() {
17961 clearTimeout(this.timeout);
17963 this.hoverState = 'out';
17965 if (!this.delay || !this.delay.hide) {
17970 this.timeout = setTimeout(function () {
17971 if (_t.hoverState == 'out') {
17974 }, this.delay.hide)
17977 show : function (on_el)
17980 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17984 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17985 if (this.html !== false) {
17986 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17988 this.el.removeClass([
17989 'fade','top','bottom', 'left', 'right','in',
17990 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17992 if (!this.title.length) {
17993 this.el.select('.popover-title',true).hide();
17996 var placement = typeof this.placement == 'function' ?
17997 this.placement.call(this, this.el, on_el) :
18000 var autoToken = /\s?auto?\s?/i;
18001 var autoPlace = autoToken.test(placement);
18003 placement = placement.replace(autoToken, '') || 'top';
18007 //this.el.setXY([0,0]);
18009 this.el.dom.style.display='block';
18010 this.el.addClass(placement);
18012 //this.el.appendTo(on_el);
18014 var p = this.getPosition();
18015 var box = this.el.getBox();
18020 var align = Roo.bootstrap.Popover.alignment[placement];
18023 this.el.alignTo(on_el, align[0],align[1]);
18024 //var arrow = this.el.select('.arrow',true).first();
18025 //arrow.set(align[2],
18027 this.el.addClass('in');
18030 if (this.el.hasClass('fade')) {
18034 this.hoverState = 'in';
18036 this.fireEvent('show', this);
18041 this.el.setXY([0,0]);
18042 this.el.removeClass('in');
18044 this.hoverState = null;
18046 this.fireEvent('hide', this);
18051 Roo.bootstrap.Popover.alignment = {
18052 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18053 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18054 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18055 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18066 * @class Roo.bootstrap.Progress
18067 * @extends Roo.bootstrap.Component
18068 * Bootstrap Progress class
18069 * @cfg {Boolean} striped striped of the progress bar
18070 * @cfg {Boolean} active animated of the progress bar
18074 * Create a new Progress
18075 * @param {Object} config The config object
18078 Roo.bootstrap.Progress = function(config){
18079 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18082 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18087 getAutoCreate : function(){
18095 cfg.cls += ' progress-striped';
18099 cfg.cls += ' active';
18118 * @class Roo.bootstrap.ProgressBar
18119 * @extends Roo.bootstrap.Component
18120 * Bootstrap ProgressBar class
18121 * @cfg {Number} aria_valuenow aria-value now
18122 * @cfg {Number} aria_valuemin aria-value min
18123 * @cfg {Number} aria_valuemax aria-value max
18124 * @cfg {String} label label for the progress bar
18125 * @cfg {String} panel (success | info | warning | danger )
18126 * @cfg {String} role role of the progress bar
18127 * @cfg {String} sr_only text
18131 * Create a new ProgressBar
18132 * @param {Object} config The config object
18135 Roo.bootstrap.ProgressBar = function(config){
18136 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18139 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18143 aria_valuemax : 100,
18149 getAutoCreate : function()
18154 cls: 'progress-bar',
18155 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18167 cfg.role = this.role;
18170 if(this.aria_valuenow){
18171 cfg['aria-valuenow'] = this.aria_valuenow;
18174 if(this.aria_valuemin){
18175 cfg['aria-valuemin'] = this.aria_valuemin;
18178 if(this.aria_valuemax){
18179 cfg['aria-valuemax'] = this.aria_valuemax;
18182 if(this.label && !this.sr_only){
18183 cfg.html = this.label;
18187 cfg.cls += ' progress-bar-' + this.panel;
18193 update : function(aria_valuenow)
18195 this.aria_valuenow = aria_valuenow;
18197 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18212 * @class Roo.bootstrap.TabGroup
18213 * @extends Roo.bootstrap.Column
18214 * Bootstrap Column class
18215 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18216 * @cfg {Boolean} carousel true to make the group behave like a carousel
18217 * @cfg {Boolean} bullets show bullets for the panels
18218 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18219 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18220 * @cfg {Boolean} showarrow (true|false) show arrow default true
18223 * Create a new TabGroup
18224 * @param {Object} config The config object
18227 Roo.bootstrap.TabGroup = function(config){
18228 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18230 this.navId = Roo.id();
18233 Roo.bootstrap.TabGroup.register(this);
18237 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18240 transition : false,
18245 slideOnTouch : false,
18248 getAutoCreate : function()
18250 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18252 cfg.cls += ' tab-content';
18254 if (this.carousel) {
18255 cfg.cls += ' carousel slide';
18258 cls : 'carousel-inner',
18262 if(this.bullets && !Roo.isTouch){
18265 cls : 'carousel-bullets',
18269 if(this.bullets_cls){
18270 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18277 cfg.cn[0].cn.push(bullets);
18280 if(this.showarrow){
18281 cfg.cn[0].cn.push({
18283 class : 'carousel-arrow',
18287 class : 'carousel-prev',
18291 class : 'fa fa-chevron-left'
18297 class : 'carousel-next',
18301 class : 'fa fa-chevron-right'
18314 initEvents: function()
18316 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18317 // this.el.on("touchstart", this.onTouchStart, this);
18320 if(this.autoslide){
18323 this.slideFn = window.setInterval(function() {
18324 _this.showPanelNext();
18328 if(this.showarrow){
18329 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18330 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18336 // onTouchStart : function(e, el, o)
18338 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18342 // this.showPanelNext();
18346 getChildContainer : function()
18348 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18352 * register a Navigation item
18353 * @param {Roo.bootstrap.NavItem} the navitem to add
18355 register : function(item)
18357 this.tabs.push( item);
18358 item.navId = this.navId; // not really needed..
18363 getActivePanel : function()
18366 Roo.each(this.tabs, function(t) {
18376 getPanelByName : function(n)
18379 Roo.each(this.tabs, function(t) {
18380 if (t.tabId == n) {
18388 indexOfPanel : function(p)
18391 Roo.each(this.tabs, function(t,i) {
18392 if (t.tabId == p.tabId) {
18401 * show a specific panel
18402 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18403 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18405 showPanel : function (pan)
18407 if(this.transition || typeof(pan) == 'undefined'){
18408 Roo.log("waiting for the transitionend");
18412 if (typeof(pan) == 'number') {
18413 pan = this.tabs[pan];
18416 if (typeof(pan) == 'string') {
18417 pan = this.getPanelByName(pan);
18420 var cur = this.getActivePanel();
18423 Roo.log('pan or acitve pan is undefined');
18427 if (pan.tabId == this.getActivePanel().tabId) {
18431 if (false === cur.fireEvent('beforedeactivate')) {
18435 if(this.bullets > 0 && !Roo.isTouch){
18436 this.setActiveBullet(this.indexOfPanel(pan));
18439 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18441 //class="carousel-item carousel-item-next carousel-item-left"
18443 this.transition = true;
18444 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18445 var lr = dir == 'next' ? 'left' : 'right';
18446 pan.el.addClass(dir); // or prev
18447 pan.el.addClass('carousel-item-' + dir); // or prev
18448 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18449 cur.el.addClass(lr); // or right
18450 pan.el.addClass(lr);
18451 cur.el.addClass('carousel-item-' +lr); // or right
18452 pan.el.addClass('carousel-item-' +lr);
18456 cur.el.on('transitionend', function() {
18457 Roo.log("trans end?");
18459 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18460 pan.setActive(true);
18462 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18463 cur.setActive(false);
18465 _this.transition = false;
18467 }, this, { single: true } );
18472 cur.setActive(false);
18473 pan.setActive(true);
18478 showPanelNext : function()
18480 var i = this.indexOfPanel(this.getActivePanel());
18482 if (i >= this.tabs.length - 1 && !this.autoslide) {
18486 if (i >= this.tabs.length - 1 && this.autoslide) {
18490 this.showPanel(this.tabs[i+1]);
18493 showPanelPrev : function()
18495 var i = this.indexOfPanel(this.getActivePanel());
18497 if (i < 1 && !this.autoslide) {
18501 if (i < 1 && this.autoslide) {
18502 i = this.tabs.length;
18505 this.showPanel(this.tabs[i-1]);
18509 addBullet: function()
18511 if(!this.bullets || Roo.isTouch){
18514 var ctr = this.el.select('.carousel-bullets',true).first();
18515 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18516 var bullet = ctr.createChild({
18517 cls : 'bullet bullet-' + i
18518 },ctr.dom.lastChild);
18523 bullet.on('click', (function(e, el, o, ii, t){
18525 e.preventDefault();
18527 this.showPanel(ii);
18529 if(this.autoslide && this.slideFn){
18530 clearInterval(this.slideFn);
18531 this.slideFn = window.setInterval(function() {
18532 _this.showPanelNext();
18536 }).createDelegate(this, [i, bullet], true));
18541 setActiveBullet : function(i)
18547 Roo.each(this.el.select('.bullet', true).elements, function(el){
18548 el.removeClass('selected');
18551 var bullet = this.el.select('.bullet-' + i, true).first();
18557 bullet.addClass('selected');
18568 Roo.apply(Roo.bootstrap.TabGroup, {
18572 * register a Navigation Group
18573 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18575 register : function(navgrp)
18577 this.groups[navgrp.navId] = navgrp;
18581 * fetch a Navigation Group based on the navigation ID
18582 * if one does not exist , it will get created.
18583 * @param {string} the navgroup to add
18584 * @returns {Roo.bootstrap.NavGroup} the navgroup
18586 get: function(navId) {
18587 if (typeof(this.groups[navId]) == 'undefined') {
18588 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18590 return this.groups[navId] ;
18605 * @class Roo.bootstrap.TabPanel
18606 * @extends Roo.bootstrap.Component
18607 * Bootstrap TabPanel class
18608 * @cfg {Boolean} active panel active
18609 * @cfg {String} html panel content
18610 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18611 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18612 * @cfg {String} href click to link..
18616 * Create a new TabPanel
18617 * @param {Object} config The config object
18620 Roo.bootstrap.TabPanel = function(config){
18621 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18625 * Fires when the active status changes
18626 * @param {Roo.bootstrap.TabPanel} this
18627 * @param {Boolean} state the new state
18632 * @event beforedeactivate
18633 * Fires before a tab is de-activated - can be used to do validation on a form.
18634 * @param {Roo.bootstrap.TabPanel} this
18635 * @return {Boolean} false if there is an error
18638 'beforedeactivate': true
18641 this.tabId = this.tabId || Roo.id();
18645 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18653 getAutoCreate : function(){
18658 // item is needed for carousel - not sure if it has any effect otherwise
18659 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18660 html: this.html || ''
18664 cfg.cls += ' active';
18668 cfg.tabId = this.tabId;
18676 initEvents: function()
18678 var p = this.parent();
18680 this.navId = this.navId || p.navId;
18682 if (typeof(this.navId) != 'undefined') {
18683 // not really needed.. but just in case.. parent should be a NavGroup.
18684 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18688 var i = tg.tabs.length - 1;
18690 if(this.active && tg.bullets > 0 && i < tg.bullets){
18691 tg.setActiveBullet(i);
18695 this.el.on('click', this.onClick, this);
18698 this.el.on("touchstart", this.onTouchStart, this);
18699 this.el.on("touchmove", this.onTouchMove, this);
18700 this.el.on("touchend", this.onTouchEnd, this);
18705 onRender : function(ct, position)
18707 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18710 setActive : function(state)
18712 Roo.log("panel - set active " + this.tabId + "=" + state);
18714 this.active = state;
18716 this.el.removeClass('active');
18718 } else if (!this.el.hasClass('active')) {
18719 this.el.addClass('active');
18722 this.fireEvent('changed', this, state);
18725 onClick : function(e)
18727 e.preventDefault();
18729 if(!this.href.length){
18733 window.location.href = this.href;
18742 onTouchStart : function(e)
18744 this.swiping = false;
18746 this.startX = e.browserEvent.touches[0].clientX;
18747 this.startY = e.browserEvent.touches[0].clientY;
18750 onTouchMove : function(e)
18752 this.swiping = true;
18754 this.endX = e.browserEvent.touches[0].clientX;
18755 this.endY = e.browserEvent.touches[0].clientY;
18758 onTouchEnd : function(e)
18765 var tabGroup = this.parent();
18767 if(this.endX > this.startX){ // swiping right
18768 tabGroup.showPanelPrev();
18772 if(this.startX > this.endX){ // swiping left
18773 tabGroup.showPanelNext();
18792 * @class Roo.bootstrap.DateField
18793 * @extends Roo.bootstrap.Input
18794 * Bootstrap DateField class
18795 * @cfg {Number} weekStart default 0
18796 * @cfg {String} viewMode default empty, (months|years)
18797 * @cfg {String} minViewMode default empty, (months|years)
18798 * @cfg {Number} startDate default -Infinity
18799 * @cfg {Number} endDate default Infinity
18800 * @cfg {Boolean} todayHighlight default false
18801 * @cfg {Boolean} todayBtn default false
18802 * @cfg {Boolean} calendarWeeks default false
18803 * @cfg {Object} daysOfWeekDisabled default empty
18804 * @cfg {Boolean} singleMode default false (true | false)
18806 * @cfg {Boolean} keyboardNavigation default true
18807 * @cfg {String} language default en
18810 * Create a new DateField
18811 * @param {Object} config The config object
18814 Roo.bootstrap.DateField = function(config){
18815 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18819 * Fires when this field show.
18820 * @param {Roo.bootstrap.DateField} this
18821 * @param {Mixed} date The date value
18826 * Fires when this field hide.
18827 * @param {Roo.bootstrap.DateField} this
18828 * @param {Mixed} date The date value
18833 * Fires when select a date.
18834 * @param {Roo.bootstrap.DateField} this
18835 * @param {Mixed} date The date value
18839 * @event beforeselect
18840 * Fires when before select a date.
18841 * @param {Roo.bootstrap.DateField} this
18842 * @param {Mixed} date The date value
18844 beforeselect : true
18848 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18851 * @cfg {String} format
18852 * The default date format string which can be overriden for localization support. The format must be
18853 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18857 * @cfg {String} altFormats
18858 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18859 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18861 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18869 todayHighlight : false,
18875 keyboardNavigation: true,
18877 calendarWeeks: false,
18879 startDate: -Infinity,
18883 daysOfWeekDisabled: [],
18887 singleMode : false,
18889 UTCDate: function()
18891 return new Date(Date.UTC.apply(Date, arguments));
18894 UTCToday: function()
18896 var today = new Date();
18897 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18900 getDate: function() {
18901 var d = this.getUTCDate();
18902 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18905 getUTCDate: function() {
18909 setDate: function(d) {
18910 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18913 setUTCDate: function(d) {
18915 this.setValue(this.formatDate(this.date));
18918 onRender: function(ct, position)
18921 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18923 this.language = this.language || 'en';
18924 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18925 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18927 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18928 this.format = this.format || 'm/d/y';
18929 this.isInline = false;
18930 this.isInput = true;
18931 this.component = this.el.select('.add-on', true).first() || false;
18932 this.component = (this.component && this.component.length === 0) ? false : this.component;
18933 this.hasInput = this.component && this.inputEl().length;
18935 if (typeof(this.minViewMode === 'string')) {
18936 switch (this.minViewMode) {
18938 this.minViewMode = 1;
18941 this.minViewMode = 2;
18944 this.minViewMode = 0;
18949 if (typeof(this.viewMode === 'string')) {
18950 switch (this.viewMode) {
18963 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18965 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18967 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18969 this.picker().on('mousedown', this.onMousedown, this);
18970 this.picker().on('click', this.onClick, this);
18972 this.picker().addClass('datepicker-dropdown');
18974 this.startViewMode = this.viewMode;
18976 if(this.singleMode){
18977 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18978 v.setVisibilityMode(Roo.Element.DISPLAY);
18982 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18983 v.setStyle('width', '189px');
18987 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18988 if(!this.calendarWeeks){
18993 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18994 v.attr('colspan', function(i, val){
18995 return parseInt(val) + 1;
19000 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
19002 this.setStartDate(this.startDate);
19003 this.setEndDate(this.endDate);
19005 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
19012 if(this.isInline) {
19017 picker : function()
19019 return this.pickerEl;
19020 // return this.el.select('.datepicker', true).first();
19023 fillDow: function()
19025 var dowCnt = this.weekStart;
19034 if(this.calendarWeeks){
19042 while (dowCnt < this.weekStart + 7) {
19046 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19050 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19053 fillMonths: function()
19056 var months = this.picker().select('>.datepicker-months td', true).first();
19058 months.dom.innerHTML = '';
19064 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19067 months.createChild(month);
19074 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;
19076 if (this.date < this.startDate) {
19077 this.viewDate = new Date(this.startDate);
19078 } else if (this.date > this.endDate) {
19079 this.viewDate = new Date(this.endDate);
19081 this.viewDate = new Date(this.date);
19089 var d = new Date(this.viewDate),
19090 year = d.getUTCFullYear(),
19091 month = d.getUTCMonth(),
19092 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19093 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19094 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19095 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19096 currentDate = this.date && this.date.valueOf(),
19097 today = this.UTCToday();
19099 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19101 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19103 // this.picker.select('>tfoot th.today').
19104 // .text(dates[this.language].today)
19105 // .toggle(this.todayBtn !== false);
19107 this.updateNavArrows();
19110 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19112 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19114 prevMonth.setUTCDate(day);
19116 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19118 var nextMonth = new Date(prevMonth);
19120 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19122 nextMonth = nextMonth.valueOf();
19124 var fillMonths = false;
19126 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19128 while(prevMonth.valueOf() <= nextMonth) {
19131 if (prevMonth.getUTCDay() === this.weekStart) {
19133 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19141 if(this.calendarWeeks){
19142 // ISO 8601: First week contains first thursday.
19143 // ISO also states week starts on Monday, but we can be more abstract here.
19145 // Start of current week: based on weekstart/current date
19146 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19147 // Thursday of this week
19148 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19149 // First Thursday of year, year from thursday
19150 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19151 // Calendar week: ms between thursdays, div ms per day, div 7 days
19152 calWeek = (th - yth) / 864e5 / 7 + 1;
19154 fillMonths.cn.push({
19162 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19164 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19167 if (this.todayHighlight &&
19168 prevMonth.getUTCFullYear() == today.getFullYear() &&
19169 prevMonth.getUTCMonth() == today.getMonth() &&
19170 prevMonth.getUTCDate() == today.getDate()) {
19171 clsName += ' today';
19174 if (currentDate && prevMonth.valueOf() === currentDate) {
19175 clsName += ' active';
19178 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19179 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19180 clsName += ' disabled';
19183 fillMonths.cn.push({
19185 cls: 'day ' + clsName,
19186 html: prevMonth.getDate()
19189 prevMonth.setDate(prevMonth.getDate()+1);
19192 var currentYear = this.date && this.date.getUTCFullYear();
19193 var currentMonth = this.date && this.date.getUTCMonth();
19195 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19197 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19198 v.removeClass('active');
19200 if(currentYear === year && k === currentMonth){
19201 v.addClass('active');
19204 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19205 v.addClass('disabled');
19211 year = parseInt(year/10, 10) * 10;
19213 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19215 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19218 for (var i = -1; i < 11; i++) {
19219 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19221 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19229 showMode: function(dir)
19232 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19235 Roo.each(this.picker().select('>div',true).elements, function(v){
19236 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19239 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19244 if(this.isInline) {
19248 this.picker().removeClass(['bottom', 'top']);
19250 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19252 * place to the top of element!
19256 this.picker().addClass('top');
19257 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19262 this.picker().addClass('bottom');
19264 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19267 parseDate : function(value)
19269 if(!value || value instanceof Date){
19272 var v = Date.parseDate(value, this.format);
19273 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19274 v = Date.parseDate(value, 'Y-m-d');
19276 if(!v && this.altFormats){
19277 if(!this.altFormatsArray){
19278 this.altFormatsArray = this.altFormats.split("|");
19280 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19281 v = Date.parseDate(value, this.altFormatsArray[i]);
19287 formatDate : function(date, fmt)
19289 return (!date || !(date instanceof Date)) ?
19290 date : date.dateFormat(fmt || this.format);
19293 onFocus : function()
19295 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19299 onBlur : function()
19301 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19303 var d = this.inputEl().getValue();
19310 showPopup : function()
19312 this.picker().show();
19316 this.fireEvent('showpopup', this, this.date);
19319 hidePopup : function()
19321 if(this.isInline) {
19324 this.picker().hide();
19325 this.viewMode = this.startViewMode;
19328 this.fireEvent('hidepopup', this, this.date);
19332 onMousedown: function(e)
19334 e.stopPropagation();
19335 e.preventDefault();
19340 Roo.bootstrap.DateField.superclass.keyup.call(this);
19344 setValue: function(v)
19346 if(this.fireEvent('beforeselect', this, v) !== false){
19347 var d = new Date(this.parseDate(v) ).clearTime();
19349 if(isNaN(d.getTime())){
19350 this.date = this.viewDate = '';
19351 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19355 v = this.formatDate(d);
19357 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19359 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19363 this.fireEvent('select', this, this.date);
19367 getValue: function()
19369 return this.formatDate(this.date);
19372 fireKey: function(e)
19374 if (!this.picker().isVisible()){
19375 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19381 var dateChanged = false,
19383 newDate, newViewDate;
19388 e.preventDefault();
19392 if (!this.keyboardNavigation) {
19395 dir = e.keyCode == 37 ? -1 : 1;
19398 newDate = this.moveYear(this.date, dir);
19399 newViewDate = this.moveYear(this.viewDate, dir);
19400 } else if (e.shiftKey){
19401 newDate = this.moveMonth(this.date, dir);
19402 newViewDate = this.moveMonth(this.viewDate, dir);
19404 newDate = new Date(this.date);
19405 newDate.setUTCDate(this.date.getUTCDate() + dir);
19406 newViewDate = new Date(this.viewDate);
19407 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19409 if (this.dateWithinRange(newDate)){
19410 this.date = newDate;
19411 this.viewDate = newViewDate;
19412 this.setValue(this.formatDate(this.date));
19414 e.preventDefault();
19415 dateChanged = true;
19420 if (!this.keyboardNavigation) {
19423 dir = e.keyCode == 38 ? -1 : 1;
19425 newDate = this.moveYear(this.date, dir);
19426 newViewDate = this.moveYear(this.viewDate, dir);
19427 } else if (e.shiftKey){
19428 newDate = this.moveMonth(this.date, dir);
19429 newViewDate = this.moveMonth(this.viewDate, dir);
19431 newDate = new Date(this.date);
19432 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19433 newViewDate = new Date(this.viewDate);
19434 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19436 if (this.dateWithinRange(newDate)){
19437 this.date = newDate;
19438 this.viewDate = newViewDate;
19439 this.setValue(this.formatDate(this.date));
19441 e.preventDefault();
19442 dateChanged = true;
19446 this.setValue(this.formatDate(this.date));
19448 e.preventDefault();
19451 this.setValue(this.formatDate(this.date));
19465 onClick: function(e)
19467 e.stopPropagation();
19468 e.preventDefault();
19470 var target = e.getTarget();
19472 if(target.nodeName.toLowerCase() === 'i'){
19473 target = Roo.get(target).dom.parentNode;
19476 var nodeName = target.nodeName;
19477 var className = target.className;
19478 var html = target.innerHTML;
19479 //Roo.log(nodeName);
19481 switch(nodeName.toLowerCase()) {
19483 switch(className) {
19489 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19490 switch(this.viewMode){
19492 this.viewDate = this.moveMonth(this.viewDate, dir);
19496 this.viewDate = this.moveYear(this.viewDate, dir);
19502 var date = new Date();
19503 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19505 this.setValue(this.formatDate(this.date));
19512 if (className.indexOf('disabled') < 0) {
19513 this.viewDate.setUTCDate(1);
19514 if (className.indexOf('month') > -1) {
19515 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19517 var year = parseInt(html, 10) || 0;
19518 this.viewDate.setUTCFullYear(year);
19522 if(this.singleMode){
19523 this.setValue(this.formatDate(this.viewDate));
19534 //Roo.log(className);
19535 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19536 var day = parseInt(html, 10) || 1;
19537 var year = this.viewDate.getUTCFullYear(),
19538 month = this.viewDate.getUTCMonth();
19540 if (className.indexOf('old') > -1) {
19547 } else if (className.indexOf('new') > -1) {
19555 //Roo.log([year,month,day]);
19556 this.date = this.UTCDate(year, month, day,0,0,0,0);
19557 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19559 //Roo.log(this.formatDate(this.date));
19560 this.setValue(this.formatDate(this.date));
19567 setStartDate: function(startDate)
19569 this.startDate = startDate || -Infinity;
19570 if (this.startDate !== -Infinity) {
19571 this.startDate = this.parseDate(this.startDate);
19574 this.updateNavArrows();
19577 setEndDate: function(endDate)
19579 this.endDate = endDate || Infinity;
19580 if (this.endDate !== Infinity) {
19581 this.endDate = this.parseDate(this.endDate);
19584 this.updateNavArrows();
19587 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19589 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19590 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19591 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19593 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19594 return parseInt(d, 10);
19597 this.updateNavArrows();
19600 updateNavArrows: function()
19602 if(this.singleMode){
19606 var d = new Date(this.viewDate),
19607 year = d.getUTCFullYear(),
19608 month = d.getUTCMonth();
19610 Roo.each(this.picker().select('.prev', true).elements, function(v){
19612 switch (this.viewMode) {
19615 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19621 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19628 Roo.each(this.picker().select('.next', true).elements, function(v){
19630 switch (this.viewMode) {
19633 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19639 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19647 moveMonth: function(date, dir)
19652 var new_date = new Date(date.valueOf()),
19653 day = new_date.getUTCDate(),
19654 month = new_date.getUTCMonth(),
19655 mag = Math.abs(dir),
19657 dir = dir > 0 ? 1 : -1;
19660 // If going back one month, make sure month is not current month
19661 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19663 return new_date.getUTCMonth() == month;
19665 // If going forward one month, make sure month is as expected
19666 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19668 return new_date.getUTCMonth() != new_month;
19670 new_month = month + dir;
19671 new_date.setUTCMonth(new_month);
19672 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19673 if (new_month < 0 || new_month > 11) {
19674 new_month = (new_month + 12) % 12;
19677 // For magnitudes >1, move one month at a time...
19678 for (var i=0; i<mag; i++) {
19679 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19680 new_date = this.moveMonth(new_date, dir);
19682 // ...then reset the day, keeping it in the new month
19683 new_month = new_date.getUTCMonth();
19684 new_date.setUTCDate(day);
19686 return new_month != new_date.getUTCMonth();
19689 // Common date-resetting loop -- if date is beyond end of month, make it
19692 new_date.setUTCDate(--day);
19693 new_date.setUTCMonth(new_month);
19698 moveYear: function(date, dir)
19700 return this.moveMonth(date, dir*12);
19703 dateWithinRange: function(date)
19705 return date >= this.startDate && date <= this.endDate;
19711 this.picker().remove();
19714 validateValue : function(value)
19716 if(this.getVisibilityEl().hasClass('hidden')){
19720 if(value.length < 1) {
19721 if(this.allowBlank){
19727 if(value.length < this.minLength){
19730 if(value.length > this.maxLength){
19734 var vt = Roo.form.VTypes;
19735 if(!vt[this.vtype](value, this)){
19739 if(typeof this.validator == "function"){
19740 var msg = this.validator(value);
19746 if(this.regex && !this.regex.test(value)){
19750 if(typeof(this.parseDate(value)) == 'undefined'){
19754 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19758 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19768 this.date = this.viewDate = '';
19770 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19775 Roo.apply(Roo.bootstrap.DateField, {
19786 html: '<i class="fa fa-arrow-left"/>'
19796 html: '<i class="fa fa-arrow-right"/>'
19838 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19839 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19840 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19841 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19842 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19855 navFnc: 'FullYear',
19860 navFnc: 'FullYear',
19865 Roo.apply(Roo.bootstrap.DateField, {
19869 cls: 'datepicker dropdown-menu roo-dynamic',
19873 cls: 'datepicker-days',
19877 cls: 'table-condensed',
19879 Roo.bootstrap.DateField.head,
19883 Roo.bootstrap.DateField.footer
19890 cls: 'datepicker-months',
19894 cls: 'table-condensed',
19896 Roo.bootstrap.DateField.head,
19897 Roo.bootstrap.DateField.content,
19898 Roo.bootstrap.DateField.footer
19905 cls: 'datepicker-years',
19909 cls: 'table-condensed',
19911 Roo.bootstrap.DateField.head,
19912 Roo.bootstrap.DateField.content,
19913 Roo.bootstrap.DateField.footer
19932 * @class Roo.bootstrap.TimeField
19933 * @extends Roo.bootstrap.Input
19934 * Bootstrap DateField class
19938 * Create a new TimeField
19939 * @param {Object} config The config object
19942 Roo.bootstrap.TimeField = function(config){
19943 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19947 * Fires when this field show.
19948 * @param {Roo.bootstrap.DateField} thisthis
19949 * @param {Mixed} date The date value
19954 * Fires when this field hide.
19955 * @param {Roo.bootstrap.DateField} this
19956 * @param {Mixed} date The date value
19961 * Fires when select a date.
19962 * @param {Roo.bootstrap.DateField} this
19963 * @param {Mixed} date The date value
19969 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19972 * @cfg {String} format
19973 * The default time format string which can be overriden for localization support. The format must be
19974 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19978 onRender: function(ct, position)
19981 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19983 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19985 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19987 this.pop = this.picker().select('>.datepicker-time',true).first();
19988 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19990 this.picker().on('mousedown', this.onMousedown, this);
19991 this.picker().on('click', this.onClick, this);
19993 this.picker().addClass('datepicker-dropdown');
19998 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19999 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
20000 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
20001 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
20002 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
20003 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
20007 fireKey: function(e){
20008 if (!this.picker().isVisible()){
20009 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20015 e.preventDefault();
20023 this.onTogglePeriod();
20026 this.onIncrementMinutes();
20029 this.onDecrementMinutes();
20038 onClick: function(e) {
20039 e.stopPropagation();
20040 e.preventDefault();
20043 picker : function()
20045 return this.el.select('.datepicker', true).first();
20048 fillTime: function()
20050 var time = this.pop.select('tbody', true).first();
20052 time.dom.innerHTML = '';
20067 cls: 'hours-up glyphicon glyphicon-chevron-up'
20087 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20108 cls: 'timepicker-hour',
20123 cls: 'timepicker-minute',
20138 cls: 'btn btn-primary period',
20160 cls: 'hours-down glyphicon glyphicon-chevron-down'
20180 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20198 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20205 var hours = this.time.getHours();
20206 var minutes = this.time.getMinutes();
20219 hours = hours - 12;
20223 hours = '0' + hours;
20227 minutes = '0' + minutes;
20230 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20231 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20232 this.pop.select('button', true).first().dom.innerHTML = period;
20238 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20240 var cls = ['bottom'];
20242 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20249 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20254 this.picker().addClass(cls.join('-'));
20258 Roo.each(cls, function(c){
20260 _this.picker().setTop(_this.inputEl().getHeight());
20264 _this.picker().setTop(0 - _this.picker().getHeight());
20269 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20273 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20280 onFocus : function()
20282 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20286 onBlur : function()
20288 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20294 this.picker().show();
20299 this.fireEvent('show', this, this.date);
20304 this.picker().hide();
20307 this.fireEvent('hide', this, this.date);
20310 setTime : function()
20313 this.setValue(this.time.format(this.format));
20315 this.fireEvent('select', this, this.date);
20320 onMousedown: function(e){
20321 e.stopPropagation();
20322 e.preventDefault();
20325 onIncrementHours: function()
20327 Roo.log('onIncrementHours');
20328 this.time = this.time.add(Date.HOUR, 1);
20333 onDecrementHours: function()
20335 Roo.log('onDecrementHours');
20336 this.time = this.time.add(Date.HOUR, -1);
20340 onIncrementMinutes: function()
20342 Roo.log('onIncrementMinutes');
20343 this.time = this.time.add(Date.MINUTE, 1);
20347 onDecrementMinutes: function()
20349 Roo.log('onDecrementMinutes');
20350 this.time = this.time.add(Date.MINUTE, -1);
20354 onTogglePeriod: function()
20356 Roo.log('onTogglePeriod');
20357 this.time = this.time.add(Date.HOUR, 12);
20364 Roo.apply(Roo.bootstrap.TimeField, {
20394 cls: 'btn btn-info ok',
20406 Roo.apply(Roo.bootstrap.TimeField, {
20410 cls: 'datepicker dropdown-menu',
20414 cls: 'datepicker-time',
20418 cls: 'table-condensed',
20420 Roo.bootstrap.TimeField.content,
20421 Roo.bootstrap.TimeField.footer
20440 * @class Roo.bootstrap.MonthField
20441 * @extends Roo.bootstrap.Input
20442 * Bootstrap MonthField class
20444 * @cfg {String} language default en
20447 * Create a new MonthField
20448 * @param {Object} config The config object
20451 Roo.bootstrap.MonthField = function(config){
20452 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20457 * Fires when this field show.
20458 * @param {Roo.bootstrap.MonthField} this
20459 * @param {Mixed} date The date value
20464 * Fires when this field hide.
20465 * @param {Roo.bootstrap.MonthField} this
20466 * @param {Mixed} date The date value
20471 * Fires when select a date.
20472 * @param {Roo.bootstrap.MonthField} this
20473 * @param {String} oldvalue The old value
20474 * @param {String} newvalue The new value
20480 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20482 onRender: function(ct, position)
20485 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20487 this.language = this.language || 'en';
20488 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20489 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20491 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20492 this.isInline = false;
20493 this.isInput = true;
20494 this.component = this.el.select('.add-on', true).first() || false;
20495 this.component = (this.component && this.component.length === 0) ? false : this.component;
20496 this.hasInput = this.component && this.inputEL().length;
20498 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20500 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20502 this.picker().on('mousedown', this.onMousedown, this);
20503 this.picker().on('click', this.onClick, this);
20505 this.picker().addClass('datepicker-dropdown');
20507 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20508 v.setStyle('width', '189px');
20515 if(this.isInline) {
20521 setValue: function(v, suppressEvent)
20523 var o = this.getValue();
20525 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20529 if(suppressEvent !== true){
20530 this.fireEvent('select', this, o, v);
20535 getValue: function()
20540 onClick: function(e)
20542 e.stopPropagation();
20543 e.preventDefault();
20545 var target = e.getTarget();
20547 if(target.nodeName.toLowerCase() === 'i'){
20548 target = Roo.get(target).dom.parentNode;
20551 var nodeName = target.nodeName;
20552 var className = target.className;
20553 var html = target.innerHTML;
20555 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20559 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20561 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20567 picker : function()
20569 return this.pickerEl;
20572 fillMonths: function()
20575 var months = this.picker().select('>.datepicker-months td', true).first();
20577 months.dom.innerHTML = '';
20583 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20586 months.createChild(month);
20595 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20596 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20599 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20600 e.removeClass('active');
20602 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20603 e.addClass('active');
20610 if(this.isInline) {
20614 this.picker().removeClass(['bottom', 'top']);
20616 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20618 * place to the top of element!
20622 this.picker().addClass('top');
20623 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20628 this.picker().addClass('bottom');
20630 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20633 onFocus : function()
20635 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20639 onBlur : function()
20641 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20643 var d = this.inputEl().getValue();
20652 this.picker().show();
20653 this.picker().select('>.datepicker-months', true).first().show();
20657 this.fireEvent('show', this, this.date);
20662 if(this.isInline) {
20665 this.picker().hide();
20666 this.fireEvent('hide', this, this.date);
20670 onMousedown: function(e)
20672 e.stopPropagation();
20673 e.preventDefault();
20678 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20682 fireKey: function(e)
20684 if (!this.picker().isVisible()){
20685 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20696 e.preventDefault();
20700 dir = e.keyCode == 37 ? -1 : 1;
20702 this.vIndex = this.vIndex + dir;
20704 if(this.vIndex < 0){
20708 if(this.vIndex > 11){
20712 if(isNaN(this.vIndex)){
20716 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20722 dir = e.keyCode == 38 ? -1 : 1;
20724 this.vIndex = this.vIndex + dir * 4;
20726 if(this.vIndex < 0){
20730 if(this.vIndex > 11){
20734 if(isNaN(this.vIndex)){
20738 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20743 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20744 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20748 e.preventDefault();
20751 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20752 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20768 this.picker().remove();
20773 Roo.apply(Roo.bootstrap.MonthField, {
20792 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20793 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20798 Roo.apply(Roo.bootstrap.MonthField, {
20802 cls: 'datepicker dropdown-menu roo-dynamic',
20806 cls: 'datepicker-months',
20810 cls: 'table-condensed',
20812 Roo.bootstrap.DateField.content
20832 * @class Roo.bootstrap.CheckBox
20833 * @extends Roo.bootstrap.Input
20834 * Bootstrap CheckBox class
20836 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20837 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20838 * @cfg {String} boxLabel The text that appears beside the checkbox
20839 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20840 * @cfg {Boolean} checked initnal the element
20841 * @cfg {Boolean} inline inline the element (default false)
20842 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20843 * @cfg {String} tooltip label tooltip
20846 * Create a new CheckBox
20847 * @param {Object} config The config object
20850 Roo.bootstrap.CheckBox = function(config){
20851 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20856 * Fires when the element is checked or unchecked.
20857 * @param {Roo.bootstrap.CheckBox} this This input
20858 * @param {Boolean} checked The new checked value
20863 * Fires when the element is click.
20864 * @param {Roo.bootstrap.CheckBox} this This input
20871 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20873 inputType: 'checkbox',
20882 getAutoCreate : function()
20884 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20890 cfg.cls = 'form-group ' + this.inputType; //input-group
20893 cfg.cls += ' ' + this.inputType + '-inline';
20899 type : this.inputType,
20900 value : this.inputValue,
20901 cls : 'roo-' + this.inputType, //'form-box',
20902 placeholder : this.placeholder || ''
20906 if(this.inputType != 'radio'){
20910 cls : 'roo-hidden-value',
20911 value : this.checked ? this.inputValue : this.valueOff
20916 if (this.weight) { // Validity check?
20917 cfg.cls += " " + this.inputType + "-" + this.weight;
20920 if (this.disabled) {
20921 input.disabled=true;
20925 input.checked = this.checked;
20930 input.name = this.name;
20932 if(this.inputType != 'radio'){
20933 hidden.name = this.name;
20934 input.name = '_hidden_' + this.name;
20939 input.cls += ' input-' + this.size;
20944 ['xs','sm','md','lg'].map(function(size){
20945 if (settings[size]) {
20946 cfg.cls += ' col-' + size + '-' + settings[size];
20950 var inputblock = input;
20952 if (this.before || this.after) {
20955 cls : 'input-group',
20960 inputblock.cn.push({
20962 cls : 'input-group-addon',
20967 inputblock.cn.push(input);
20969 if(this.inputType != 'radio'){
20970 inputblock.cn.push(hidden);
20974 inputblock.cn.push({
20976 cls : 'input-group-addon',
20983 if (align ==='left' && this.fieldLabel.length) {
20984 // Roo.log("left and has label");
20989 cls : 'control-label',
20990 html : this.fieldLabel
21000 if(this.labelWidth > 12){
21001 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
21004 if(this.labelWidth < 13 && this.labelmd == 0){
21005 this.labelmd = this.labelWidth;
21008 if(this.labellg > 0){
21009 cfg.cn[0].cls += ' col-lg-' + this.labellg;
21010 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
21013 if(this.labelmd > 0){
21014 cfg.cn[0].cls += ' col-md-' + this.labelmd;
21015 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
21018 if(this.labelsm > 0){
21019 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
21020 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
21023 if(this.labelxs > 0){
21024 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
21025 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
21028 } else if ( this.fieldLabel.length) {
21029 // Roo.log(" label");
21033 tag: this.boxLabel ? 'span' : 'label',
21035 cls: 'control-label box-input-label',
21036 //cls : 'input-group-addon',
21037 html : this.fieldLabel
21046 // Roo.log(" no label && no align");
21047 cfg.cn = [ inputblock ] ;
21053 var boxLabelCfg = {
21055 //'for': id, // box label is handled by onclick - so no for...
21057 html: this.boxLabel
21061 boxLabelCfg.tooltip = this.tooltip;
21064 cfg.cn.push(boxLabelCfg);
21067 if(this.inputType != 'radio'){
21068 cfg.cn.push(hidden);
21076 * return the real input element.
21078 inputEl: function ()
21080 return this.el.select('input.roo-' + this.inputType,true).first();
21082 hiddenEl: function ()
21084 return this.el.select('input.roo-hidden-value',true).first();
21087 labelEl: function()
21089 return this.el.select('label.control-label',true).first();
21091 /* depricated... */
21095 return this.labelEl();
21098 boxLabelEl: function()
21100 return this.el.select('label.box-label',true).first();
21103 initEvents : function()
21105 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21107 this.inputEl().on('click', this.onClick, this);
21109 if (this.boxLabel) {
21110 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21113 this.startValue = this.getValue();
21116 Roo.bootstrap.CheckBox.register(this);
21120 onClick : function(e)
21122 if(this.fireEvent('click', this, e) !== false){
21123 this.setChecked(!this.checked);
21128 setChecked : function(state,suppressEvent)
21130 this.startValue = this.getValue();
21132 if(this.inputType == 'radio'){
21134 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21135 e.dom.checked = false;
21138 this.inputEl().dom.checked = true;
21140 this.inputEl().dom.value = this.inputValue;
21142 if(suppressEvent !== true){
21143 this.fireEvent('check', this, true);
21151 this.checked = state;
21153 this.inputEl().dom.checked = state;
21156 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21158 if(suppressEvent !== true){
21159 this.fireEvent('check', this, state);
21165 getValue : function()
21167 if(this.inputType == 'radio'){
21168 return this.getGroupValue();
21171 return this.hiddenEl().dom.value;
21175 getGroupValue : function()
21177 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21181 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21184 setValue : function(v,suppressEvent)
21186 if(this.inputType == 'radio'){
21187 this.setGroupValue(v, suppressEvent);
21191 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21196 setGroupValue : function(v, suppressEvent)
21198 this.startValue = this.getValue();
21200 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21201 e.dom.checked = false;
21203 if(e.dom.value == v){
21204 e.dom.checked = true;
21208 if(suppressEvent !== true){
21209 this.fireEvent('check', this, true);
21217 validate : function()
21219 if(this.getVisibilityEl().hasClass('hidden')){
21225 (this.inputType == 'radio' && this.validateRadio()) ||
21226 (this.inputType == 'checkbox' && this.validateCheckbox())
21232 this.markInvalid();
21236 validateRadio : function()
21238 if(this.getVisibilityEl().hasClass('hidden')){
21242 if(this.allowBlank){
21248 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21249 if(!e.dom.checked){
21261 validateCheckbox : function()
21264 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21265 //return (this.getValue() == this.inputValue) ? true : false;
21268 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21276 for(var i in group){
21277 if(group[i].el.isVisible(true)){
21285 for(var i in group){
21290 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21297 * Mark this field as valid
21299 markValid : function()
21303 this.fireEvent('valid', this);
21305 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21308 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21315 if(this.inputType == 'radio'){
21316 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21317 var fg = e.findParent('.form-group', false, true);
21318 if (Roo.bootstrap.version == 3) {
21319 fg.removeClass([_this.invalidClass, _this.validClass]);
21320 fg.addClass(_this.validClass);
21322 fg.removeClass(['is-valid', 'is-invalid']);
21323 fg.addClass('is-valid');
21331 var fg = this.el.findParent('.form-group', false, true);
21332 if (Roo.bootstrap.version == 3) {
21333 fg.removeClass([this.invalidClass, this.validClass]);
21334 fg.addClass(this.validClass);
21336 fg.removeClass(['is-valid', 'is-invalid']);
21337 fg.addClass('is-valid');
21342 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21348 for(var i in group){
21349 var fg = group[i].el.findParent('.form-group', false, true);
21350 if (Roo.bootstrap.version == 3) {
21351 fg.removeClass([this.invalidClass, this.validClass]);
21352 fg.addClass(this.validClass);
21354 fg.removeClass(['is-valid', 'is-invalid']);
21355 fg.addClass('is-valid');
21361 * Mark this field as invalid
21362 * @param {String} msg The validation message
21364 markInvalid : function(msg)
21366 if(this.allowBlank){
21372 this.fireEvent('invalid', this, msg);
21374 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21377 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21381 label.markInvalid();
21384 if(this.inputType == 'radio'){
21386 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21387 var fg = e.findParent('.form-group', false, true);
21388 if (Roo.bootstrap.version == 3) {
21389 fg.removeClass([_this.invalidClass, _this.validClass]);
21390 fg.addClass(_this.invalidClass);
21392 fg.removeClass(['is-invalid', 'is-valid']);
21393 fg.addClass('is-invalid');
21401 var fg = this.el.findParent('.form-group', false, true);
21402 if (Roo.bootstrap.version == 3) {
21403 fg.removeClass([_this.invalidClass, _this.validClass]);
21404 fg.addClass(_this.invalidClass);
21406 fg.removeClass(['is-invalid', 'is-valid']);
21407 fg.addClass('is-invalid');
21412 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21418 for(var i in group){
21419 var fg = group[i].el.findParent('.form-group', false, true);
21420 if (Roo.bootstrap.version == 3) {
21421 fg.removeClass([_this.invalidClass, _this.validClass]);
21422 fg.addClass(_this.invalidClass);
21424 fg.removeClass(['is-invalid', 'is-valid']);
21425 fg.addClass('is-invalid');
21431 clearInvalid : function()
21433 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21435 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21437 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21439 if (label && label.iconEl) {
21440 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21441 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21445 disable : function()
21447 if(this.inputType != 'radio'){
21448 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21455 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21456 _this.getActionEl().addClass(this.disabledClass);
21457 e.dom.disabled = true;
21461 this.disabled = true;
21462 this.fireEvent("disable", this);
21466 enable : function()
21468 if(this.inputType != 'radio'){
21469 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21476 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21477 _this.getActionEl().removeClass(this.disabledClass);
21478 e.dom.disabled = false;
21482 this.disabled = false;
21483 this.fireEvent("enable", this);
21487 setBoxLabel : function(v)
21492 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21498 Roo.apply(Roo.bootstrap.CheckBox, {
21503 * register a CheckBox Group
21504 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21506 register : function(checkbox)
21508 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21509 this.groups[checkbox.groupId] = {};
21512 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21516 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21520 * fetch a CheckBox Group based on the group ID
21521 * @param {string} the group ID
21522 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21524 get: function(groupId) {
21525 if (typeof(this.groups[groupId]) == 'undefined') {
21529 return this.groups[groupId] ;
21542 * @class Roo.bootstrap.Radio
21543 * @extends Roo.bootstrap.Component
21544 * Bootstrap Radio class
21545 * @cfg {String} boxLabel - the label associated
21546 * @cfg {String} value - the value of radio
21549 * Create a new Radio
21550 * @param {Object} config The config object
21552 Roo.bootstrap.Radio = function(config){
21553 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21557 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21563 getAutoCreate : function()
21567 cls : 'form-group radio',
21572 html : this.boxLabel
21580 initEvents : function()
21582 this.parent().register(this);
21584 this.el.on('click', this.onClick, this);
21588 onClick : function(e)
21590 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21591 this.setChecked(true);
21595 setChecked : function(state, suppressEvent)
21597 this.parent().setValue(this.value, suppressEvent);
21601 setBoxLabel : function(v)
21606 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21621 * @class Roo.bootstrap.SecurePass
21622 * @extends Roo.bootstrap.Input
21623 * Bootstrap SecurePass class
21627 * Create a new SecurePass
21628 * @param {Object} config The config object
21631 Roo.bootstrap.SecurePass = function (config) {
21632 // these go here, so the translation tool can replace them..
21634 PwdEmpty: "Please type a password, and then retype it to confirm.",
21635 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21636 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21637 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21638 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21639 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21640 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21641 TooWeak: "Your password is Too Weak."
21643 this.meterLabel = "Password strength:";
21644 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21645 this.meterClass = [
21646 "roo-password-meter-tooweak",
21647 "roo-password-meter-weak",
21648 "roo-password-meter-medium",
21649 "roo-password-meter-strong",
21650 "roo-password-meter-grey"
21655 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21658 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21660 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21662 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21663 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21664 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21665 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21666 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21667 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21668 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21678 * @cfg {String/Object} Label for the strength meter (defaults to
21679 * 'Password strength:')
21684 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21685 * ['Weak', 'Medium', 'Strong'])
21688 pwdStrengths: false,
21701 initEvents: function ()
21703 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21705 if (this.el.is('input[type=password]') && Roo.isSafari) {
21706 this.el.on('keydown', this.SafariOnKeyDown, this);
21709 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21712 onRender: function (ct, position)
21714 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21715 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21716 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21718 this.trigger.createChild({
21723 cls: 'roo-password-meter-grey col-xs-12',
21726 //width: this.meterWidth + 'px'
21730 cls: 'roo-password-meter-text'
21736 if (this.hideTrigger) {
21737 this.trigger.setDisplayed(false);
21739 this.setSize(this.width || '', this.height || '');
21742 onDestroy: function ()
21744 if (this.trigger) {
21745 this.trigger.removeAllListeners();
21746 this.trigger.remove();
21749 this.wrap.remove();
21751 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21754 checkStrength: function ()
21756 var pwd = this.inputEl().getValue();
21757 if (pwd == this._lastPwd) {
21762 if (this.ClientSideStrongPassword(pwd)) {
21764 } else if (this.ClientSideMediumPassword(pwd)) {
21766 } else if (this.ClientSideWeakPassword(pwd)) {
21772 Roo.log('strength1: ' + strength);
21774 //var pm = this.trigger.child('div/div/div').dom;
21775 var pm = this.trigger.child('div/div');
21776 pm.removeClass(this.meterClass);
21777 pm.addClass(this.meterClass[strength]);
21780 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21782 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21784 this._lastPwd = pwd;
21788 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21790 this._lastPwd = '';
21792 var pm = this.trigger.child('div/div');
21793 pm.removeClass(this.meterClass);
21794 pm.addClass('roo-password-meter-grey');
21797 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21800 this.inputEl().dom.type='password';
21803 validateValue: function (value)
21806 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21809 if (value.length == 0) {
21810 if (this.allowBlank) {
21811 this.clearInvalid();
21815 this.markInvalid(this.errors.PwdEmpty);
21816 this.errorMsg = this.errors.PwdEmpty;
21824 if ('[\x21-\x7e]*'.match(value)) {
21825 this.markInvalid(this.errors.PwdBadChar);
21826 this.errorMsg = this.errors.PwdBadChar;
21829 if (value.length < 6) {
21830 this.markInvalid(this.errors.PwdShort);
21831 this.errorMsg = this.errors.PwdShort;
21834 if (value.length > 16) {
21835 this.markInvalid(this.errors.PwdLong);
21836 this.errorMsg = this.errors.PwdLong;
21840 if (this.ClientSideStrongPassword(value)) {
21842 } else if (this.ClientSideMediumPassword(value)) {
21844 } else if (this.ClientSideWeakPassword(value)) {
21851 if (strength < 2) {
21852 //this.markInvalid(this.errors.TooWeak);
21853 this.errorMsg = this.errors.TooWeak;
21858 console.log('strength2: ' + strength);
21860 //var pm = this.trigger.child('div/div/div').dom;
21862 var pm = this.trigger.child('div/div');
21863 pm.removeClass(this.meterClass);
21864 pm.addClass(this.meterClass[strength]);
21866 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21868 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21870 this.errorMsg = '';
21874 CharacterSetChecks: function (type)
21877 this.fResult = false;
21880 isctype: function (character, type)
21883 case this.kCapitalLetter:
21884 if (character >= 'A' && character <= 'Z') {
21889 case this.kSmallLetter:
21890 if (character >= 'a' && character <= 'z') {
21896 if (character >= '0' && character <= '9') {
21901 case this.kPunctuation:
21902 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21913 IsLongEnough: function (pwd, size)
21915 return !(pwd == null || isNaN(size) || pwd.length < size);
21918 SpansEnoughCharacterSets: function (word, nb)
21920 if (!this.IsLongEnough(word, nb))
21925 var characterSetChecks = new Array(
21926 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21927 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21930 for (var index = 0; index < word.length; ++index) {
21931 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21932 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21933 characterSetChecks[nCharSet].fResult = true;
21940 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21941 if (characterSetChecks[nCharSet].fResult) {
21946 if (nCharSets < nb) {
21952 ClientSideStrongPassword: function (pwd)
21954 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21957 ClientSideMediumPassword: function (pwd)
21959 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21962 ClientSideWeakPassword: function (pwd)
21964 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21967 })//<script type="text/javascript">
21970 * Based Ext JS Library 1.1.1
21971 * Copyright(c) 2006-2007, Ext JS, LLC.
21977 * @class Roo.HtmlEditorCore
21978 * @extends Roo.Component
21979 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21981 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21984 Roo.HtmlEditorCore = function(config){
21987 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21992 * @event initialize
21993 * Fires when the editor is fully initialized (including the iframe)
21994 * @param {Roo.HtmlEditorCore} this
21999 * Fires when the editor is first receives the focus. Any insertion must wait
22000 * until after this event.
22001 * @param {Roo.HtmlEditorCore} this
22005 * @event beforesync
22006 * Fires before the textarea is updated with content from the editor iframe. Return false
22007 * to cancel the sync.
22008 * @param {Roo.HtmlEditorCore} this
22009 * @param {String} html
22013 * @event beforepush
22014 * Fires before the iframe editor is updated with content from the textarea. Return false
22015 * to cancel the push.
22016 * @param {Roo.HtmlEditorCore} this
22017 * @param {String} html
22022 * Fires when the textarea is updated with content from the editor iframe.
22023 * @param {Roo.HtmlEditorCore} this
22024 * @param {String} html
22029 * Fires when the iframe editor is updated with content from the textarea.
22030 * @param {Roo.HtmlEditorCore} this
22031 * @param {String} html
22036 * @event editorevent
22037 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22038 * @param {Roo.HtmlEditorCore} this
22044 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22046 // defaults : white / black...
22047 this.applyBlacklists();
22054 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22058 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22064 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22069 * @cfg {Number} height (in pixels)
22073 * @cfg {Number} width (in pixels)
22078 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22081 stylesheets: false,
22086 // private properties
22087 validationEvent : false,
22089 initialized : false,
22091 sourceEditMode : false,
22092 onFocus : Roo.emptyFn,
22094 hideMode:'offsets',
22098 // blacklist + whitelisted elements..
22105 * Protected method that will not generally be called directly. It
22106 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22107 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22109 getDocMarkup : function(){
22113 // inherit styels from page...??
22114 if (this.stylesheets === false) {
22116 Roo.get(document.head).select('style').each(function(node) {
22117 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22120 Roo.get(document.head).select('link').each(function(node) {
22121 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22124 } else if (!this.stylesheets.length) {
22126 st = '<style type="text/css">' +
22127 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22130 st = '<style type="text/css">' +
22135 st += '<style type="text/css">' +
22136 'IMG { cursor: pointer } ' +
22139 var cls = 'roo-htmleditor-body';
22141 if(this.bodyCls.length){
22142 cls += ' ' + this.bodyCls;
22145 return '<html><head>' + st +
22146 //<style type="text/css">' +
22147 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22149 ' </head><body class="' + cls + '"></body></html>';
22153 onRender : function(ct, position)
22156 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22157 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22160 this.el.dom.style.border = '0 none';
22161 this.el.dom.setAttribute('tabIndex', -1);
22162 this.el.addClass('x-hidden hide');
22166 if(Roo.isIE){ // fix IE 1px bogus margin
22167 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22171 this.frameId = Roo.id();
22175 var iframe = this.owner.wrap.createChild({
22177 cls: 'form-control', // bootstrap..
22179 name: this.frameId,
22180 frameBorder : 'no',
22181 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22186 this.iframe = iframe.dom;
22188 this.assignDocWin();
22190 this.doc.designMode = 'on';
22193 this.doc.write(this.getDocMarkup());
22197 var task = { // must defer to wait for browser to be ready
22199 //console.log("run task?" + this.doc.readyState);
22200 this.assignDocWin();
22201 if(this.doc.body || this.doc.readyState == 'complete'){
22203 this.doc.designMode="on";
22207 Roo.TaskMgr.stop(task);
22208 this.initEditor.defer(10, this);
22215 Roo.TaskMgr.start(task);
22220 onResize : function(w, h)
22222 Roo.log('resize: ' +w + ',' + h );
22223 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22227 if(typeof w == 'number'){
22229 this.iframe.style.width = w + 'px';
22231 if(typeof h == 'number'){
22233 this.iframe.style.height = h + 'px';
22235 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22242 * Toggles the editor between standard and source edit mode.
22243 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22245 toggleSourceEdit : function(sourceEditMode){
22247 this.sourceEditMode = sourceEditMode === true;
22249 if(this.sourceEditMode){
22251 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22254 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22255 //this.iframe.className = '';
22258 //this.setSize(this.owner.wrap.getSize());
22259 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22266 * Protected method that will not generally be called directly. If you need/want
22267 * custom HTML cleanup, this is the method you should override.
22268 * @param {String} html The HTML to be cleaned
22269 * return {String} The cleaned HTML
22271 cleanHtml : function(html){
22272 html = String(html);
22273 if(html.length > 5){
22274 if(Roo.isSafari){ // strip safari nonsense
22275 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22278 if(html == ' '){
22285 * HTML Editor -> Textarea
22286 * Protected method that will not generally be called directly. Syncs the contents
22287 * of the editor iframe with the textarea.
22289 syncValue : function(){
22290 if(this.initialized){
22291 var bd = (this.doc.body || this.doc.documentElement);
22292 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22293 var html = bd.innerHTML;
22295 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22296 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22298 html = '<div style="'+m[0]+'">' + html + '</div>';
22301 html = this.cleanHtml(html);
22302 // fix up the special chars.. normaly like back quotes in word...
22303 // however we do not want to do this with chinese..
22304 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22305 var cc = b.charCodeAt();
22307 (cc >= 0x4E00 && cc < 0xA000 ) ||
22308 (cc >= 0x3400 && cc < 0x4E00 ) ||
22309 (cc >= 0xf900 && cc < 0xfb00 )
22315 if(this.owner.fireEvent('beforesync', this, html) !== false){
22316 this.el.dom.value = html;
22317 this.owner.fireEvent('sync', this, html);
22323 * Protected method that will not generally be called directly. Pushes the value of the textarea
22324 * into the iframe editor.
22326 pushValue : function(){
22327 if(this.initialized){
22328 var v = this.el.dom.value.trim();
22330 // if(v.length < 1){
22334 if(this.owner.fireEvent('beforepush', this, v) !== false){
22335 var d = (this.doc.body || this.doc.documentElement);
22337 this.cleanUpPaste();
22338 this.el.dom.value = d.innerHTML;
22339 this.owner.fireEvent('push', this, v);
22345 deferFocus : function(){
22346 this.focus.defer(10, this);
22350 focus : function(){
22351 if(this.win && !this.sourceEditMode){
22358 assignDocWin: function()
22360 var iframe = this.iframe;
22363 this.doc = iframe.contentWindow.document;
22364 this.win = iframe.contentWindow;
22366 // if (!Roo.get(this.frameId)) {
22369 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22370 // this.win = Roo.get(this.frameId).dom.contentWindow;
22372 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22376 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22377 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22382 initEditor : function(){
22383 //console.log("INIT EDITOR");
22384 this.assignDocWin();
22388 this.doc.designMode="on";
22390 this.doc.write(this.getDocMarkup());
22393 var dbody = (this.doc.body || this.doc.documentElement);
22394 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22395 // this copies styles from the containing element into thsi one..
22396 // not sure why we need all of this..
22397 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22399 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22400 //ss['background-attachment'] = 'fixed'; // w3c
22401 dbody.bgProperties = 'fixed'; // ie
22402 //Roo.DomHelper.applyStyles(dbody, ss);
22403 Roo.EventManager.on(this.doc, {
22404 //'mousedown': this.onEditorEvent,
22405 'mouseup': this.onEditorEvent,
22406 'dblclick': this.onEditorEvent,
22407 'click': this.onEditorEvent,
22408 'keyup': this.onEditorEvent,
22413 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22415 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22416 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22418 this.initialized = true;
22420 this.owner.fireEvent('initialize', this);
22425 onDestroy : function(){
22431 //for (var i =0; i < this.toolbars.length;i++) {
22432 // // fixme - ask toolbars for heights?
22433 // this.toolbars[i].onDestroy();
22436 //this.wrap.dom.innerHTML = '';
22437 //this.wrap.remove();
22442 onFirstFocus : function(){
22444 this.assignDocWin();
22447 this.activated = true;
22450 if(Roo.isGecko){ // prevent silly gecko errors
22452 var s = this.win.getSelection();
22453 if(!s.focusNode || s.focusNode.nodeType != 3){
22454 var r = s.getRangeAt(0);
22455 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22460 this.execCmd('useCSS', true);
22461 this.execCmd('styleWithCSS', false);
22464 this.owner.fireEvent('activate', this);
22468 adjustFont: function(btn){
22469 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22470 //if(Roo.isSafari){ // safari
22473 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22474 if(Roo.isSafari){ // safari
22475 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22476 v = (v < 10) ? 10 : v;
22477 v = (v > 48) ? 48 : v;
22478 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22483 v = Math.max(1, v+adjust);
22485 this.execCmd('FontSize', v );
22488 onEditorEvent : function(e)
22490 this.owner.fireEvent('editorevent', this, e);
22491 // this.updateToolbar();
22492 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22495 insertTag : function(tg)
22497 // could be a bit smarter... -> wrap the current selected tRoo..
22498 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22500 range = this.createRange(this.getSelection());
22501 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22502 wrappingNode.appendChild(range.extractContents());
22503 range.insertNode(wrappingNode);
22510 this.execCmd("formatblock", tg);
22514 insertText : function(txt)
22518 var range = this.createRange();
22519 range.deleteContents();
22520 //alert(Sender.getAttribute('label'));
22522 range.insertNode(this.doc.createTextNode(txt));
22528 * Executes a Midas editor command on the editor document and performs necessary focus and
22529 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22530 * @param {String} cmd The Midas command
22531 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22533 relayCmd : function(cmd, value){
22535 this.execCmd(cmd, value);
22536 this.owner.fireEvent('editorevent', this);
22537 //this.updateToolbar();
22538 this.owner.deferFocus();
22542 * Executes a Midas editor command directly on the editor document.
22543 * For visual commands, you should use {@link #relayCmd} instead.
22544 * <b>This should only be called after the editor is initialized.</b>
22545 * @param {String} cmd The Midas command
22546 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22548 execCmd : function(cmd, value){
22549 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22556 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22558 * @param {String} text | dom node..
22560 insertAtCursor : function(text)
22563 if(!this.activated){
22569 var r = this.doc.selection.createRange();
22580 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22584 // from jquery ui (MIT licenced)
22586 var win = this.win;
22588 if (win.getSelection && win.getSelection().getRangeAt) {
22589 range = win.getSelection().getRangeAt(0);
22590 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22591 range.insertNode(node);
22592 } else if (win.document.selection && win.document.selection.createRange) {
22593 // no firefox support
22594 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22595 win.document.selection.createRange().pasteHTML(txt);
22597 // no firefox support
22598 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22599 this.execCmd('InsertHTML', txt);
22608 mozKeyPress : function(e){
22610 var c = e.getCharCode(), cmd;
22613 c = String.fromCharCode(c).toLowerCase();
22627 this.cleanUpPaste.defer(100, this);
22635 e.preventDefault();
22643 fixKeys : function(){ // load time branching for fastest keydown performance
22645 return function(e){
22646 var k = e.getKey(), r;
22649 r = this.doc.selection.createRange();
22652 r.pasteHTML('    ');
22659 r = this.doc.selection.createRange();
22661 var target = r.parentElement();
22662 if(!target || target.tagName.toLowerCase() != 'li'){
22664 r.pasteHTML('<br />');
22670 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22671 this.cleanUpPaste.defer(100, this);
22677 }else if(Roo.isOpera){
22678 return function(e){
22679 var k = e.getKey();
22683 this.execCmd('InsertHTML','    ');
22686 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22687 this.cleanUpPaste.defer(100, this);
22692 }else if(Roo.isSafari){
22693 return function(e){
22694 var k = e.getKey();
22698 this.execCmd('InsertText','\t');
22702 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22703 this.cleanUpPaste.defer(100, this);
22711 getAllAncestors: function()
22713 var p = this.getSelectedNode();
22716 a.push(p); // push blank onto stack..
22717 p = this.getParentElement();
22721 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22725 a.push(this.doc.body);
22729 lastSelNode : false,
22732 getSelection : function()
22734 this.assignDocWin();
22735 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22738 getSelectedNode: function()
22740 // this may only work on Gecko!!!
22742 // should we cache this!!!!
22747 var range = this.createRange(this.getSelection()).cloneRange();
22750 var parent = range.parentElement();
22752 var testRange = range.duplicate();
22753 testRange.moveToElementText(parent);
22754 if (testRange.inRange(range)) {
22757 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22760 parent = parent.parentElement;
22765 // is ancestor a text element.
22766 var ac = range.commonAncestorContainer;
22767 if (ac.nodeType == 3) {
22768 ac = ac.parentNode;
22771 var ar = ac.childNodes;
22774 var other_nodes = [];
22775 var has_other_nodes = false;
22776 for (var i=0;i<ar.length;i++) {
22777 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22780 // fullly contained node.
22782 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22787 // probably selected..
22788 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22789 other_nodes.push(ar[i]);
22793 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22798 has_other_nodes = true;
22800 if (!nodes.length && other_nodes.length) {
22801 nodes= other_nodes;
22803 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22809 createRange: function(sel)
22811 // this has strange effects when using with
22812 // top toolbar - not sure if it's a great idea.
22813 //this.editor.contentWindow.focus();
22814 if (typeof sel != "undefined") {
22816 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22818 return this.doc.createRange();
22821 return this.doc.createRange();
22824 getParentElement: function()
22827 this.assignDocWin();
22828 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22830 var range = this.createRange(sel);
22833 var p = range.commonAncestorContainer;
22834 while (p.nodeType == 3) { // text node
22845 * Range intersection.. the hard stuff...
22849 * [ -- selected range --- ]
22853 * if end is before start or hits it. fail.
22854 * if start is after end or hits it fail.
22856 * if either hits (but other is outside. - then it's not
22862 // @see http://www.thismuchiknow.co.uk/?p=64.
22863 rangeIntersectsNode : function(range, node)
22865 var nodeRange = node.ownerDocument.createRange();
22867 nodeRange.selectNode(node);
22869 nodeRange.selectNodeContents(node);
22872 var rangeStartRange = range.cloneRange();
22873 rangeStartRange.collapse(true);
22875 var rangeEndRange = range.cloneRange();
22876 rangeEndRange.collapse(false);
22878 var nodeStartRange = nodeRange.cloneRange();
22879 nodeStartRange.collapse(true);
22881 var nodeEndRange = nodeRange.cloneRange();
22882 nodeEndRange.collapse(false);
22884 return rangeStartRange.compareBoundaryPoints(
22885 Range.START_TO_START, nodeEndRange) == -1 &&
22886 rangeEndRange.compareBoundaryPoints(
22887 Range.START_TO_START, nodeStartRange) == 1;
22891 rangeCompareNode : function(range, node)
22893 var nodeRange = node.ownerDocument.createRange();
22895 nodeRange.selectNode(node);
22897 nodeRange.selectNodeContents(node);
22901 range.collapse(true);
22903 nodeRange.collapse(true);
22905 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22906 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22908 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22910 var nodeIsBefore = ss == 1;
22911 var nodeIsAfter = ee == -1;
22913 if (nodeIsBefore && nodeIsAfter) {
22916 if (!nodeIsBefore && nodeIsAfter) {
22917 return 1; //right trailed.
22920 if (nodeIsBefore && !nodeIsAfter) {
22921 return 2; // left trailed.
22927 // private? - in a new class?
22928 cleanUpPaste : function()
22930 // cleans up the whole document..
22931 Roo.log('cleanuppaste');
22933 this.cleanUpChildren(this.doc.body);
22934 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22935 if (clean != this.doc.body.innerHTML) {
22936 this.doc.body.innerHTML = clean;
22941 cleanWordChars : function(input) {// change the chars to hex code
22942 var he = Roo.HtmlEditorCore;
22944 var output = input;
22945 Roo.each(he.swapCodes, function(sw) {
22946 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22948 output = output.replace(swapper, sw[1]);
22955 cleanUpChildren : function (n)
22957 if (!n.childNodes.length) {
22960 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22961 this.cleanUpChild(n.childNodes[i]);
22968 cleanUpChild : function (node)
22971 //console.log(node);
22972 if (node.nodeName == "#text") {
22973 // clean up silly Windows -- stuff?
22976 if (node.nodeName == "#comment") {
22977 node.parentNode.removeChild(node);
22978 // clean up silly Windows -- stuff?
22981 var lcname = node.tagName.toLowerCase();
22982 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22983 // whitelist of tags..
22985 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22987 node.parentNode.removeChild(node);
22992 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22994 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22995 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22997 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22998 // remove_keep_children = true;
23001 if (remove_keep_children) {
23002 this.cleanUpChildren(node);
23003 // inserts everything just before this node...
23004 while (node.childNodes.length) {
23005 var cn = node.childNodes[0];
23006 node.removeChild(cn);
23007 node.parentNode.insertBefore(cn, node);
23009 node.parentNode.removeChild(node);
23013 if (!node.attributes || !node.attributes.length) {
23014 this.cleanUpChildren(node);
23018 function cleanAttr(n,v)
23021 if (v.match(/^\./) || v.match(/^\//)) {
23024 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
23027 if (v.match(/^#/)) {
23030 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
23031 node.removeAttribute(n);
23035 var cwhite = this.cwhite;
23036 var cblack = this.cblack;
23038 function cleanStyle(n,v)
23040 if (v.match(/expression/)) { //XSS?? should we even bother..
23041 node.removeAttribute(n);
23045 var parts = v.split(/;/);
23048 Roo.each(parts, function(p) {
23049 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23053 var l = p.split(':').shift().replace(/\s+/g,'');
23054 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23056 if ( cwhite.length && cblack.indexOf(l) > -1) {
23057 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23058 //node.removeAttribute(n);
23062 // only allow 'c whitelisted system attributes'
23063 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23064 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23065 //node.removeAttribute(n);
23075 if (clean.length) {
23076 node.setAttribute(n, clean.join(';'));
23078 node.removeAttribute(n);
23084 for (var i = node.attributes.length-1; i > -1 ; i--) {
23085 var a = node.attributes[i];
23088 if (a.name.toLowerCase().substr(0,2)=='on') {
23089 node.removeAttribute(a.name);
23092 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23093 node.removeAttribute(a.name);
23096 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23097 cleanAttr(a.name,a.value); // fixme..
23100 if (a.name == 'style') {
23101 cleanStyle(a.name,a.value);
23104 /// clean up MS crap..
23105 // tecnically this should be a list of valid class'es..
23108 if (a.name == 'class') {
23109 if (a.value.match(/^Mso/)) {
23110 node.className = '';
23113 if (a.value.match(/^body$/)) {
23114 node.className = '';
23125 this.cleanUpChildren(node);
23131 * Clean up MS wordisms...
23133 cleanWord : function(node)
23138 this.cleanWord(this.doc.body);
23141 if (node.nodeName == "#text") {
23142 // clean up silly Windows -- stuff?
23145 if (node.nodeName == "#comment") {
23146 node.parentNode.removeChild(node);
23147 // clean up silly Windows -- stuff?
23151 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23152 node.parentNode.removeChild(node);
23156 // remove - but keep children..
23157 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23158 while (node.childNodes.length) {
23159 var cn = node.childNodes[0];
23160 node.removeChild(cn);
23161 node.parentNode.insertBefore(cn, node);
23163 node.parentNode.removeChild(node);
23164 this.iterateChildren(node, this.cleanWord);
23168 if (node.className.length) {
23170 var cn = node.className.split(/\W+/);
23172 Roo.each(cn, function(cls) {
23173 if (cls.match(/Mso[a-zA-Z]+/)) {
23178 node.className = cna.length ? cna.join(' ') : '';
23180 node.removeAttribute("class");
23184 if (node.hasAttribute("lang")) {
23185 node.removeAttribute("lang");
23188 if (node.hasAttribute("style")) {
23190 var styles = node.getAttribute("style").split(";");
23192 Roo.each(styles, function(s) {
23193 if (!s.match(/:/)) {
23196 var kv = s.split(":");
23197 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23200 // what ever is left... we allow.
23203 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23204 if (!nstyle.length) {
23205 node.removeAttribute('style');
23208 this.iterateChildren(node, this.cleanWord);
23214 * iterateChildren of a Node, calling fn each time, using this as the scole..
23215 * @param {DomNode} node node to iterate children of.
23216 * @param {Function} fn method of this class to call on each item.
23218 iterateChildren : function(node, fn)
23220 if (!node.childNodes.length) {
23223 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23224 fn.call(this, node.childNodes[i])
23230 * cleanTableWidths.
23232 * Quite often pasting from word etc.. results in tables with column and widths.
23233 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23236 cleanTableWidths : function(node)
23241 this.cleanTableWidths(this.doc.body);
23246 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23249 Roo.log(node.tagName);
23250 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23251 this.iterateChildren(node, this.cleanTableWidths);
23254 if (node.hasAttribute('width')) {
23255 node.removeAttribute('width');
23259 if (node.hasAttribute("style")) {
23262 var styles = node.getAttribute("style").split(";");
23264 Roo.each(styles, function(s) {
23265 if (!s.match(/:/)) {
23268 var kv = s.split(":");
23269 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23272 // what ever is left... we allow.
23275 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23276 if (!nstyle.length) {
23277 node.removeAttribute('style');
23281 this.iterateChildren(node, this.cleanTableWidths);
23289 domToHTML : function(currentElement, depth, nopadtext) {
23291 depth = depth || 0;
23292 nopadtext = nopadtext || false;
23294 if (!currentElement) {
23295 return this.domToHTML(this.doc.body);
23298 //Roo.log(currentElement);
23300 var allText = false;
23301 var nodeName = currentElement.nodeName;
23302 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23304 if (nodeName == '#text') {
23306 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23311 if (nodeName != 'BODY') {
23314 // Prints the node tagName, such as <A>, <IMG>, etc
23317 for(i = 0; i < currentElement.attributes.length;i++) {
23319 var aname = currentElement.attributes.item(i).name;
23320 if (!currentElement.attributes.item(i).value.length) {
23323 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23326 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23335 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23338 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23343 // Traverse the tree
23345 var currentElementChild = currentElement.childNodes.item(i);
23346 var allText = true;
23347 var innerHTML = '';
23349 while (currentElementChild) {
23350 // Formatting code (indent the tree so it looks nice on the screen)
23351 var nopad = nopadtext;
23352 if (lastnode == 'SPAN') {
23356 if (currentElementChild.nodeName == '#text') {
23357 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23358 toadd = nopadtext ? toadd : toadd.trim();
23359 if (!nopad && toadd.length > 80) {
23360 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23362 innerHTML += toadd;
23365 currentElementChild = currentElement.childNodes.item(i);
23371 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23373 // Recursively traverse the tree structure of the child node
23374 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23375 lastnode = currentElementChild.nodeName;
23377 currentElementChild=currentElement.childNodes.item(i);
23383 // The remaining code is mostly for formatting the tree
23384 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23389 ret+= "</"+tagName+">";
23395 applyBlacklists : function()
23397 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23398 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23402 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23403 if (b.indexOf(tag) > -1) {
23406 this.white.push(tag);
23410 Roo.each(w, function(tag) {
23411 if (b.indexOf(tag) > -1) {
23414 if (this.white.indexOf(tag) > -1) {
23417 this.white.push(tag);
23422 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23423 if (w.indexOf(tag) > -1) {
23426 this.black.push(tag);
23430 Roo.each(b, function(tag) {
23431 if (w.indexOf(tag) > -1) {
23434 if (this.black.indexOf(tag) > -1) {
23437 this.black.push(tag);
23442 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23443 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23447 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23448 if (b.indexOf(tag) > -1) {
23451 this.cwhite.push(tag);
23455 Roo.each(w, function(tag) {
23456 if (b.indexOf(tag) > -1) {
23459 if (this.cwhite.indexOf(tag) > -1) {
23462 this.cwhite.push(tag);
23467 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23468 if (w.indexOf(tag) > -1) {
23471 this.cblack.push(tag);
23475 Roo.each(b, function(tag) {
23476 if (w.indexOf(tag) > -1) {
23479 if (this.cblack.indexOf(tag) > -1) {
23482 this.cblack.push(tag);
23487 setStylesheets : function(stylesheets)
23489 if(typeof(stylesheets) == 'string'){
23490 Roo.get(this.iframe.contentDocument.head).createChild({
23492 rel : 'stylesheet',
23501 Roo.each(stylesheets, function(s) {
23506 Roo.get(_this.iframe.contentDocument.head).createChild({
23508 rel : 'stylesheet',
23517 removeStylesheets : function()
23521 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23526 setStyle : function(style)
23528 Roo.get(this.iframe.contentDocument.head).createChild({
23537 // hide stuff that is not compatible
23551 * @event specialkey
23555 * @cfg {String} fieldClass @hide
23558 * @cfg {String} focusClass @hide
23561 * @cfg {String} autoCreate @hide
23564 * @cfg {String} inputType @hide
23567 * @cfg {String} invalidClass @hide
23570 * @cfg {String} invalidText @hide
23573 * @cfg {String} msgFx @hide
23576 * @cfg {String} validateOnBlur @hide
23580 Roo.HtmlEditorCore.white = [
23581 'area', 'br', 'img', 'input', 'hr', 'wbr',
23583 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23584 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23585 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23586 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23587 'table', 'ul', 'xmp',
23589 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23592 'dir', 'menu', 'ol', 'ul', 'dl',
23598 Roo.HtmlEditorCore.black = [
23599 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23601 'base', 'basefont', 'bgsound', 'blink', 'body',
23602 'frame', 'frameset', 'head', 'html', 'ilayer',
23603 'iframe', 'layer', 'link', 'meta', 'object',
23604 'script', 'style' ,'title', 'xml' // clean later..
23606 Roo.HtmlEditorCore.clean = [
23607 'script', 'style', 'title', 'xml'
23609 Roo.HtmlEditorCore.remove = [
23614 Roo.HtmlEditorCore.ablack = [
23618 Roo.HtmlEditorCore.aclean = [
23619 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23623 Roo.HtmlEditorCore.pwhite= [
23624 'http', 'https', 'mailto'
23627 // white listed style attributes.
23628 Roo.HtmlEditorCore.cwhite= [
23629 // 'text-align', /// default is to allow most things..
23635 // black listed style attributes.
23636 Roo.HtmlEditorCore.cblack= [
23637 // 'font-size' -- this can be set by the project
23641 Roo.HtmlEditorCore.swapCodes =[
23660 * @class Roo.bootstrap.HtmlEditor
23661 * @extends Roo.bootstrap.TextArea
23662 * Bootstrap HtmlEditor class
23665 * Create a new HtmlEditor
23666 * @param {Object} config The config object
23669 Roo.bootstrap.HtmlEditor = function(config){
23670 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23671 if (!this.toolbars) {
23672 this.toolbars = [];
23675 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23678 * @event initialize
23679 * Fires when the editor is fully initialized (including the iframe)
23680 * @param {HtmlEditor} this
23685 * Fires when the editor is first receives the focus. Any insertion must wait
23686 * until after this event.
23687 * @param {HtmlEditor} this
23691 * @event beforesync
23692 * Fires before the textarea is updated with content from the editor iframe. Return false
23693 * to cancel the sync.
23694 * @param {HtmlEditor} this
23695 * @param {String} html
23699 * @event beforepush
23700 * Fires before the iframe editor is updated with content from the textarea. Return false
23701 * to cancel the push.
23702 * @param {HtmlEditor} this
23703 * @param {String} html
23708 * Fires when the textarea is updated with content from the editor iframe.
23709 * @param {HtmlEditor} this
23710 * @param {String} html
23715 * Fires when the iframe editor is updated with content from the textarea.
23716 * @param {HtmlEditor} this
23717 * @param {String} html
23721 * @event editmodechange
23722 * Fires when the editor switches edit modes
23723 * @param {HtmlEditor} this
23724 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23726 editmodechange: true,
23728 * @event editorevent
23729 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23730 * @param {HtmlEditor} this
23734 * @event firstfocus
23735 * Fires when on first focus - needed by toolbars..
23736 * @param {HtmlEditor} this
23741 * Auto save the htmlEditor value as a file into Events
23742 * @param {HtmlEditor} this
23746 * @event savedpreview
23747 * preview the saved version of htmlEditor
23748 * @param {HtmlEditor} this
23755 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23759 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23764 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23769 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23774 * @cfg {Number} height (in pixels)
23778 * @cfg {Number} width (in pixels)
23783 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23786 stylesheets: false,
23791 // private properties
23792 validationEvent : false,
23794 initialized : false,
23797 onFocus : Roo.emptyFn,
23799 hideMode:'offsets',
23801 tbContainer : false,
23805 toolbarContainer :function() {
23806 return this.wrap.select('.x-html-editor-tb',true).first();
23810 * Protected method that will not generally be called directly. It
23811 * is called when the editor creates its toolbar. Override this method if you need to
23812 * add custom toolbar buttons.
23813 * @param {HtmlEditor} editor
23815 createToolbar : function(){
23816 Roo.log('renewing');
23817 Roo.log("create toolbars");
23819 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23820 this.toolbars[0].render(this.toolbarContainer());
23824 // if (!editor.toolbars || !editor.toolbars.length) {
23825 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23828 // for (var i =0 ; i < editor.toolbars.length;i++) {
23829 // editor.toolbars[i] = Roo.factory(
23830 // typeof(editor.toolbars[i]) == 'string' ?
23831 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23832 // Roo.bootstrap.HtmlEditor);
23833 // editor.toolbars[i].init(editor);
23839 onRender : function(ct, position)
23841 // Roo.log("Call onRender: " + this.xtype);
23843 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23845 this.wrap = this.inputEl().wrap({
23846 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23849 this.editorcore.onRender(ct, position);
23851 if (this.resizable) {
23852 this.resizeEl = new Roo.Resizable(this.wrap, {
23856 minHeight : this.height,
23857 height: this.height,
23858 handles : this.resizable,
23861 resize : function(r, w, h) {
23862 _t.onResize(w,h); // -something
23868 this.createToolbar(this);
23871 if(!this.width && this.resizable){
23872 this.setSize(this.wrap.getSize());
23874 if (this.resizeEl) {
23875 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23876 // should trigger onReize..
23882 onResize : function(w, h)
23884 Roo.log('resize: ' +w + ',' + h );
23885 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23889 if(this.inputEl() ){
23890 if(typeof w == 'number'){
23891 var aw = w - this.wrap.getFrameWidth('lr');
23892 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23895 if(typeof h == 'number'){
23896 var tbh = -11; // fixme it needs to tool bar size!
23897 for (var i =0; i < this.toolbars.length;i++) {
23898 // fixme - ask toolbars for heights?
23899 tbh += this.toolbars[i].el.getHeight();
23900 //if (this.toolbars[i].footer) {
23901 // tbh += this.toolbars[i].footer.el.getHeight();
23909 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23910 ah -= 5; // knock a few pixes off for look..
23911 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23915 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23916 this.editorcore.onResize(ew,eh);
23921 * Toggles the editor between standard and source edit mode.
23922 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23924 toggleSourceEdit : function(sourceEditMode)
23926 this.editorcore.toggleSourceEdit(sourceEditMode);
23928 if(this.editorcore.sourceEditMode){
23929 Roo.log('editor - showing textarea');
23932 // Roo.log(this.syncValue());
23934 this.inputEl().removeClass(['hide', 'x-hidden']);
23935 this.inputEl().dom.removeAttribute('tabIndex');
23936 this.inputEl().focus();
23938 Roo.log('editor - hiding textarea');
23940 // Roo.log(this.pushValue());
23943 this.inputEl().addClass(['hide', 'x-hidden']);
23944 this.inputEl().dom.setAttribute('tabIndex', -1);
23945 //this.deferFocus();
23948 if(this.resizable){
23949 this.setSize(this.wrap.getSize());
23952 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23955 // private (for BoxComponent)
23956 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23958 // private (for BoxComponent)
23959 getResizeEl : function(){
23963 // private (for BoxComponent)
23964 getPositionEl : function(){
23969 initEvents : function(){
23970 this.originalValue = this.getValue();
23974 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23977 // markInvalid : Roo.emptyFn,
23979 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23982 // clearInvalid : Roo.emptyFn,
23984 setValue : function(v){
23985 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23986 this.editorcore.pushValue();
23991 deferFocus : function(){
23992 this.focus.defer(10, this);
23996 focus : function(){
23997 this.editorcore.focus();
24003 onDestroy : function(){
24009 for (var i =0; i < this.toolbars.length;i++) {
24010 // fixme - ask toolbars for heights?
24011 this.toolbars[i].onDestroy();
24014 this.wrap.dom.innerHTML = '';
24015 this.wrap.remove();
24020 onFirstFocus : function(){
24021 //Roo.log("onFirstFocus");
24022 this.editorcore.onFirstFocus();
24023 for (var i =0; i < this.toolbars.length;i++) {
24024 this.toolbars[i].onFirstFocus();
24030 syncValue : function()
24032 this.editorcore.syncValue();
24035 pushValue : function()
24037 this.editorcore.pushValue();
24041 // hide stuff that is not compatible
24055 * @event specialkey
24059 * @cfg {String} fieldClass @hide
24062 * @cfg {String} focusClass @hide
24065 * @cfg {String} autoCreate @hide
24068 * @cfg {String} inputType @hide
24072 * @cfg {String} invalidText @hide
24075 * @cfg {String} msgFx @hide
24078 * @cfg {String} validateOnBlur @hide
24087 Roo.namespace('Roo.bootstrap.htmleditor');
24089 * @class Roo.bootstrap.HtmlEditorToolbar1
24095 new Roo.bootstrap.HtmlEditor({
24098 new Roo.bootstrap.HtmlEditorToolbar1({
24099 disable : { fonts: 1 , format: 1, ..., ... , ...],
24105 * @cfg {Object} disable List of elements to disable..
24106 * @cfg {Array} btns List of additional buttons.
24110 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24113 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24116 Roo.apply(this, config);
24118 // default disabled, based on 'good practice'..
24119 this.disable = this.disable || {};
24120 Roo.applyIf(this.disable, {
24123 specialElements : true
24125 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24127 this.editor = config.editor;
24128 this.editorcore = config.editor.editorcore;
24130 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24132 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24133 // dont call parent... till later.
24135 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24140 editorcore : false,
24145 "h1","h2","h3","h4","h5","h6",
24147 "abbr", "acronym", "address", "cite", "samp", "var",
24151 onRender : function(ct, position)
24153 // Roo.log("Call onRender: " + this.xtype);
24155 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24157 this.el.dom.style.marginBottom = '0';
24159 var editorcore = this.editorcore;
24160 var editor= this.editor;
24163 var btn = function(id,cmd , toggle, handler, html){
24165 var event = toggle ? 'toggle' : 'click';
24170 xns: Roo.bootstrap,
24174 enableToggle:toggle !== false,
24176 pressed : toggle ? false : null,
24179 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24180 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24186 // var cb_box = function...
24191 xns: Roo.bootstrap,
24196 xns: Roo.bootstrap,
24200 Roo.each(this.formats, function(f) {
24201 style.menu.items.push({
24203 xns: Roo.bootstrap,
24204 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24209 editorcore.insertTag(this.tagname);
24216 children.push(style);
24218 btn('bold',false,true);
24219 btn('italic',false,true);
24220 btn('align-left', 'justifyleft',true);
24221 btn('align-center', 'justifycenter',true);
24222 btn('align-right' , 'justifyright',true);
24223 btn('link', false, false, function(btn) {
24224 //Roo.log("create link?");
24225 var url = prompt(this.createLinkText, this.defaultLinkValue);
24226 if(url && url != 'http:/'+'/'){
24227 this.editorcore.relayCmd('createlink', url);
24230 btn('list','insertunorderedlist',true);
24231 btn('pencil', false,true, function(btn){
24233 this.toggleSourceEdit(btn.pressed);
24236 if (this.editor.btns.length > 0) {
24237 for (var i = 0; i<this.editor.btns.length; i++) {
24238 children.push(this.editor.btns[i]);
24246 xns: Roo.bootstrap,
24251 xns: Roo.bootstrap,
24256 cog.menu.items.push({
24258 xns: Roo.bootstrap,
24259 html : Clean styles,
24264 editorcore.insertTag(this.tagname);
24273 this.xtype = 'NavSimplebar';
24275 for(var i=0;i< children.length;i++) {
24277 this.buttons.add(this.addxtypeChild(children[i]));
24281 editor.on('editorevent', this.updateToolbar, this);
24283 onBtnClick : function(id)
24285 this.editorcore.relayCmd(id);
24286 this.editorcore.focus();
24290 * Protected method that will not generally be called directly. It triggers
24291 * a toolbar update by reading the markup state of the current selection in the editor.
24293 updateToolbar: function(){
24295 if(!this.editorcore.activated){
24296 this.editor.onFirstFocus(); // is this neeed?
24300 var btns = this.buttons;
24301 var doc = this.editorcore.doc;
24302 btns.get('bold').setActive(doc.queryCommandState('bold'));
24303 btns.get('italic').setActive(doc.queryCommandState('italic'));
24304 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24306 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24307 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24308 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24310 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24311 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24314 var ans = this.editorcore.getAllAncestors();
24315 if (this.formatCombo) {
24318 var store = this.formatCombo.store;
24319 this.formatCombo.setValue("");
24320 for (var i =0; i < ans.length;i++) {
24321 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24323 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24331 // hides menus... - so this cant be on a menu...
24332 Roo.bootstrap.MenuMgr.hideAll();
24334 Roo.bootstrap.MenuMgr.hideAll();
24335 //this.editorsyncValue();
24337 onFirstFocus: function() {
24338 this.buttons.each(function(item){
24342 toggleSourceEdit : function(sourceEditMode){
24345 if(sourceEditMode){
24346 Roo.log("disabling buttons");
24347 this.buttons.each( function(item){
24348 if(item.cmd != 'pencil'){
24354 Roo.log("enabling buttons");
24355 if(this.editorcore.initialized){
24356 this.buttons.each( function(item){
24362 Roo.log("calling toggole on editor");
24363 // tell the editor that it's been pressed..
24364 this.editor.toggleSourceEdit(sourceEditMode);
24374 * @class Roo.bootstrap.Table.AbstractSelectionModel
24375 * @extends Roo.util.Observable
24376 * Abstract base class for grid SelectionModels. It provides the interface that should be
24377 * implemented by descendant classes. This class should not be directly instantiated.
24380 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24381 this.locked = false;
24382 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24386 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24387 /** @ignore Called by the grid automatically. Do not call directly. */
24388 init : function(grid){
24394 * Locks the selections.
24397 this.locked = true;
24401 * Unlocks the selections.
24403 unlock : function(){
24404 this.locked = false;
24408 * Returns true if the selections are locked.
24409 * @return {Boolean}
24411 isLocked : function(){
24412 return this.locked;
24416 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24417 * @class Roo.bootstrap.Table.RowSelectionModel
24418 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24419 * It supports multiple selections and keyboard selection/navigation.
24421 * @param {Object} config
24424 Roo.bootstrap.Table.RowSelectionModel = function(config){
24425 Roo.apply(this, config);
24426 this.selections = new Roo.util.MixedCollection(false, function(o){
24431 this.lastActive = false;
24435 * @event selectionchange
24436 * Fires when the selection changes
24437 * @param {SelectionModel} this
24439 "selectionchange" : true,
24441 * @event afterselectionchange
24442 * Fires after the selection changes (eg. by key press or clicking)
24443 * @param {SelectionModel} this
24445 "afterselectionchange" : true,
24447 * @event beforerowselect
24448 * Fires when a row is selected being selected, return false to cancel.
24449 * @param {SelectionModel} this
24450 * @param {Number} rowIndex The selected index
24451 * @param {Boolean} keepExisting False if other selections will be cleared
24453 "beforerowselect" : true,
24456 * Fires when a row is selected.
24457 * @param {SelectionModel} this
24458 * @param {Number} rowIndex The selected index
24459 * @param {Roo.data.Record} r The record
24461 "rowselect" : true,
24463 * @event rowdeselect
24464 * Fires when a row is deselected.
24465 * @param {SelectionModel} this
24466 * @param {Number} rowIndex The selected index
24468 "rowdeselect" : true
24470 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24471 this.locked = false;
24474 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24476 * @cfg {Boolean} singleSelect
24477 * True to allow selection of only one row at a time (defaults to false)
24479 singleSelect : false,
24482 initEvents : function()
24485 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24486 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24487 //}else{ // allow click to work like normal
24488 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24490 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24491 this.grid.on("rowclick", this.handleMouseDown, this);
24493 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24494 "up" : function(e){
24496 this.selectPrevious(e.shiftKey);
24497 }else if(this.last !== false && this.lastActive !== false){
24498 var last = this.last;
24499 this.selectRange(this.last, this.lastActive-1);
24500 this.grid.getView().focusRow(this.lastActive);
24501 if(last !== false){
24505 this.selectFirstRow();
24507 this.fireEvent("afterselectionchange", this);
24509 "down" : function(e){
24511 this.selectNext(e.shiftKey);
24512 }else if(this.last !== false && this.lastActive !== false){
24513 var last = this.last;
24514 this.selectRange(this.last, this.lastActive+1);
24515 this.grid.getView().focusRow(this.lastActive);
24516 if(last !== false){
24520 this.selectFirstRow();
24522 this.fireEvent("afterselectionchange", this);
24526 this.grid.store.on('load', function(){
24527 this.selections.clear();
24530 var view = this.grid.view;
24531 view.on("refresh", this.onRefresh, this);
24532 view.on("rowupdated", this.onRowUpdated, this);
24533 view.on("rowremoved", this.onRemove, this);
24538 onRefresh : function()
24540 var ds = this.grid.store, i, v = this.grid.view;
24541 var s = this.selections;
24542 s.each(function(r){
24543 if((i = ds.indexOfId(r.id)) != -1){
24552 onRemove : function(v, index, r){
24553 this.selections.remove(r);
24557 onRowUpdated : function(v, index, r){
24558 if(this.isSelected(r)){
24559 v.onRowSelect(index);
24565 * @param {Array} records The records to select
24566 * @param {Boolean} keepExisting (optional) True to keep existing selections
24568 selectRecords : function(records, keepExisting)
24571 this.clearSelections();
24573 var ds = this.grid.store;
24574 for(var i = 0, len = records.length; i < len; i++){
24575 this.selectRow(ds.indexOf(records[i]), true);
24580 * Gets the number of selected rows.
24583 getCount : function(){
24584 return this.selections.length;
24588 * Selects the first row in the grid.
24590 selectFirstRow : function(){
24595 * Select the last row.
24596 * @param {Boolean} keepExisting (optional) True to keep existing selections
24598 selectLastRow : function(keepExisting){
24599 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24600 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24604 * Selects the row immediately following the last selected row.
24605 * @param {Boolean} keepExisting (optional) True to keep existing selections
24607 selectNext : function(keepExisting)
24609 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24610 this.selectRow(this.last+1, keepExisting);
24611 this.grid.getView().focusRow(this.last);
24616 * Selects the row that precedes the last selected row.
24617 * @param {Boolean} keepExisting (optional) True to keep existing selections
24619 selectPrevious : function(keepExisting){
24621 this.selectRow(this.last-1, keepExisting);
24622 this.grid.getView().focusRow(this.last);
24627 * Returns the selected records
24628 * @return {Array} Array of selected records
24630 getSelections : function(){
24631 return [].concat(this.selections.items);
24635 * Returns the first selected record.
24638 getSelected : function(){
24639 return this.selections.itemAt(0);
24644 * Clears all selections.
24646 clearSelections : function(fast)
24652 var ds = this.grid.store;
24653 var s = this.selections;
24654 s.each(function(r){
24655 this.deselectRow(ds.indexOfId(r.id));
24659 this.selections.clear();
24666 * Selects all rows.
24668 selectAll : function(){
24672 this.selections.clear();
24673 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24674 this.selectRow(i, true);
24679 * Returns True if there is a selection.
24680 * @return {Boolean}
24682 hasSelection : function(){
24683 return this.selections.length > 0;
24687 * Returns True if the specified row is selected.
24688 * @param {Number/Record} record The record or index of the record to check
24689 * @return {Boolean}
24691 isSelected : function(index){
24692 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24693 return (r && this.selections.key(r.id) ? true : false);
24697 * Returns True if the specified record id is selected.
24698 * @param {String} id The id of record to check
24699 * @return {Boolean}
24701 isIdSelected : function(id){
24702 return (this.selections.key(id) ? true : false);
24707 handleMouseDBClick : function(e, t){
24711 handleMouseDown : function(e, t)
24713 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24714 if(this.isLocked() || rowIndex < 0 ){
24717 if(e.shiftKey && this.last !== false){
24718 var last = this.last;
24719 this.selectRange(last, rowIndex, e.ctrlKey);
24720 this.last = last; // reset the last
24724 var isSelected = this.isSelected(rowIndex);
24725 //Roo.log("select row:" + rowIndex);
24727 this.deselectRow(rowIndex);
24729 this.selectRow(rowIndex, true);
24733 if(e.button !== 0 && isSelected){
24734 alert('rowIndex 2: ' + rowIndex);
24735 view.focusRow(rowIndex);
24736 }else if(e.ctrlKey && isSelected){
24737 this.deselectRow(rowIndex);
24738 }else if(!isSelected){
24739 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24740 view.focusRow(rowIndex);
24744 this.fireEvent("afterselectionchange", this);
24747 handleDragableRowClick : function(grid, rowIndex, e)
24749 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24750 this.selectRow(rowIndex, false);
24751 grid.view.focusRow(rowIndex);
24752 this.fireEvent("afterselectionchange", this);
24757 * Selects multiple rows.
24758 * @param {Array} rows Array of the indexes of the row to select
24759 * @param {Boolean} keepExisting (optional) True to keep existing selections
24761 selectRows : function(rows, keepExisting){
24763 this.clearSelections();
24765 for(var i = 0, len = rows.length; i < len; i++){
24766 this.selectRow(rows[i], true);
24771 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24772 * @param {Number} startRow The index of the first row in the range
24773 * @param {Number} endRow The index of the last row in the range
24774 * @param {Boolean} keepExisting (optional) True to retain existing selections
24776 selectRange : function(startRow, endRow, keepExisting){
24781 this.clearSelections();
24783 if(startRow <= endRow){
24784 for(var i = startRow; i <= endRow; i++){
24785 this.selectRow(i, true);
24788 for(var i = startRow; i >= endRow; i--){
24789 this.selectRow(i, true);
24795 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24796 * @param {Number} startRow The index of the first row in the range
24797 * @param {Number} endRow The index of the last row in the range
24799 deselectRange : function(startRow, endRow, preventViewNotify){
24803 for(var i = startRow; i <= endRow; i++){
24804 this.deselectRow(i, preventViewNotify);
24810 * @param {Number} row The index of the row to select
24811 * @param {Boolean} keepExisting (optional) True to keep existing selections
24813 selectRow : function(index, keepExisting, preventViewNotify)
24815 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24818 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24819 if(!keepExisting || this.singleSelect){
24820 this.clearSelections();
24823 var r = this.grid.store.getAt(index);
24824 //console.log('selectRow - record id :' + r.id);
24826 this.selections.add(r);
24827 this.last = this.lastActive = index;
24828 if(!preventViewNotify){
24829 var proxy = new Roo.Element(
24830 this.grid.getRowDom(index)
24832 proxy.addClass('bg-info info');
24834 this.fireEvent("rowselect", this, index, r);
24835 this.fireEvent("selectionchange", this);
24841 * @param {Number} row The index of the row to deselect
24843 deselectRow : function(index, preventViewNotify)
24848 if(this.last == index){
24851 if(this.lastActive == index){
24852 this.lastActive = false;
24855 var r = this.grid.store.getAt(index);
24860 this.selections.remove(r);
24861 //.console.log('deselectRow - record id :' + r.id);
24862 if(!preventViewNotify){
24864 var proxy = new Roo.Element(
24865 this.grid.getRowDom(index)
24867 proxy.removeClass('bg-info info');
24869 this.fireEvent("rowdeselect", this, index);
24870 this.fireEvent("selectionchange", this);
24874 restoreLast : function(){
24876 this.last = this._last;
24881 acceptsNav : function(row, col, cm){
24882 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24886 onEditorKey : function(field, e){
24887 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24892 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24894 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24896 }else if(k == e.ENTER && !e.ctrlKey){
24900 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24902 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24904 }else if(k == e.ESC){
24908 g.startEditing(newCell[0], newCell[1]);
24914 * Ext JS Library 1.1.1
24915 * Copyright(c) 2006-2007, Ext JS, LLC.
24917 * Originally Released Under LGPL - original licence link has changed is not relivant.
24920 * <script type="text/javascript">
24924 * @class Roo.bootstrap.PagingToolbar
24925 * @extends Roo.bootstrap.NavSimplebar
24926 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24928 * Create a new PagingToolbar
24929 * @param {Object} config The config object
24930 * @param {Roo.data.Store} store
24932 Roo.bootstrap.PagingToolbar = function(config)
24934 // old args format still supported... - xtype is prefered..
24935 // created from xtype...
24937 this.ds = config.dataSource;
24939 if (config.store && !this.ds) {
24940 this.store= Roo.factory(config.store, Roo.data);
24941 this.ds = this.store;
24942 this.ds.xmodule = this.xmodule || false;
24945 this.toolbarItems = [];
24946 if (config.items) {
24947 this.toolbarItems = config.items;
24950 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24955 this.bind(this.ds);
24958 if (Roo.bootstrap.version == 4) {
24959 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24961 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24966 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24968 * @cfg {Roo.data.Store} dataSource
24969 * The underlying data store providing the paged data
24972 * @cfg {String/HTMLElement/Element} container
24973 * container The id or element that will contain the toolbar
24976 * @cfg {Boolean} displayInfo
24977 * True to display the displayMsg (defaults to false)
24980 * @cfg {Number} pageSize
24981 * The number of records to display per page (defaults to 20)
24985 * @cfg {String} displayMsg
24986 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24988 displayMsg : 'Displaying {0} - {1} of {2}',
24990 * @cfg {String} emptyMsg
24991 * The message to display when no records are found (defaults to "No data to display")
24993 emptyMsg : 'No data to display',
24995 * Customizable piece of the default paging text (defaults to "Page")
24998 beforePageText : "Page",
25000 * Customizable piece of the default paging text (defaults to "of %0")
25003 afterPageText : "of {0}",
25005 * Customizable piece of the default paging text (defaults to "First Page")
25008 firstText : "First Page",
25010 * Customizable piece of the default paging text (defaults to "Previous Page")
25013 prevText : "Previous Page",
25015 * Customizable piece of the default paging text (defaults to "Next Page")
25018 nextText : "Next Page",
25020 * Customizable piece of the default paging text (defaults to "Last Page")
25023 lastText : "Last Page",
25025 * Customizable piece of the default paging text (defaults to "Refresh")
25028 refreshText : "Refresh",
25032 onRender : function(ct, position)
25034 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
25035 this.navgroup.parentId = this.id;
25036 this.navgroup.onRender(this.el, null);
25037 // add the buttons to the navgroup
25039 if(this.displayInfo){
25040 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
25041 this.displayEl = this.el.select('.x-paging-info', true).first();
25042 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
25043 // this.displayEl = navel.el.select('span',true).first();
25049 Roo.each(_this.buttons, function(e){ // this might need to use render????
25050 Roo.factory(e).render(_this.el);
25054 Roo.each(_this.toolbarItems, function(e) {
25055 _this.navgroup.addItem(e);
25059 this.first = this.navgroup.addItem({
25060 tooltip: this.firstText,
25061 cls: "prev btn-outline-secondary",
25062 html : ' <i class="fa fa-step-backward"></i>',
25064 preventDefault: true,
25065 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25068 this.prev = this.navgroup.addItem({
25069 tooltip: this.prevText,
25070 cls: "prev btn-outline-secondary",
25071 html : ' <i class="fa fa-backward"></i>',
25073 preventDefault: true,
25074 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25076 //this.addSeparator();
25079 var field = this.navgroup.addItem( {
25081 cls : 'x-paging-position btn-outline-secondary',
25083 html : this.beforePageText +
25084 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25085 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25088 this.field = field.el.select('input', true).first();
25089 this.field.on("keydown", this.onPagingKeydown, this);
25090 this.field.on("focus", function(){this.dom.select();});
25093 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25094 //this.field.setHeight(18);
25095 //this.addSeparator();
25096 this.next = this.navgroup.addItem({
25097 tooltip: this.nextText,
25098 cls: "next btn-outline-secondary",
25099 html : ' <i class="fa fa-forward"></i>',
25101 preventDefault: true,
25102 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25104 this.last = this.navgroup.addItem({
25105 tooltip: this.lastText,
25106 html : ' <i class="fa fa-step-forward"></i>',
25107 cls: "next btn-outline-secondary",
25109 preventDefault: true,
25110 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25112 //this.addSeparator();
25113 this.loading = this.navgroup.addItem({
25114 tooltip: this.refreshText,
25115 cls: "btn-outline-secondary",
25116 html : ' <i class="fa fa-refresh"></i>',
25117 preventDefault: true,
25118 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25124 updateInfo : function(){
25125 if(this.displayEl){
25126 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25127 var msg = count == 0 ?
25131 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25133 this.displayEl.update(msg);
25138 onLoad : function(ds, r, o)
25140 this.cursor = o.params.start ? o.params.start : 0;
25142 var d = this.getPageData(),
25147 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25148 this.field.dom.value = ap;
25149 this.first.setDisabled(ap == 1);
25150 this.prev.setDisabled(ap == 1);
25151 this.next.setDisabled(ap == ps);
25152 this.last.setDisabled(ap == ps);
25153 this.loading.enable();
25158 getPageData : function(){
25159 var total = this.ds.getTotalCount();
25162 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25163 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25168 onLoadError : function(){
25169 this.loading.enable();
25173 onPagingKeydown : function(e){
25174 var k = e.getKey();
25175 var d = this.getPageData();
25177 var v = this.field.dom.value, pageNum;
25178 if(!v || isNaN(pageNum = parseInt(v, 10))){
25179 this.field.dom.value = d.activePage;
25182 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25183 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25186 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))
25188 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25189 this.field.dom.value = pageNum;
25190 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25193 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25195 var v = this.field.dom.value, pageNum;
25196 var increment = (e.shiftKey) ? 10 : 1;
25197 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25200 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25201 this.field.dom.value = d.activePage;
25204 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25206 this.field.dom.value = parseInt(v, 10) + increment;
25207 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25208 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25215 beforeLoad : function(){
25217 this.loading.disable();
25222 onClick : function(which){
25231 ds.load({params:{start: 0, limit: this.pageSize}});
25234 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25237 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25240 var total = ds.getTotalCount();
25241 var extra = total % this.pageSize;
25242 var lastStart = extra ? (total - extra) : total-this.pageSize;
25243 ds.load({params:{start: lastStart, limit: this.pageSize}});
25246 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25252 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25253 * @param {Roo.data.Store} store The data store to unbind
25255 unbind : function(ds){
25256 ds.un("beforeload", this.beforeLoad, this);
25257 ds.un("load", this.onLoad, this);
25258 ds.un("loadexception", this.onLoadError, this);
25259 ds.un("remove", this.updateInfo, this);
25260 ds.un("add", this.updateInfo, this);
25261 this.ds = undefined;
25265 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25266 * @param {Roo.data.Store} store The data store to bind
25268 bind : function(ds){
25269 ds.on("beforeload", this.beforeLoad, this);
25270 ds.on("load", this.onLoad, this);
25271 ds.on("loadexception", this.onLoadError, this);
25272 ds.on("remove", this.updateInfo, this);
25273 ds.on("add", this.updateInfo, this);
25284 * @class Roo.bootstrap.MessageBar
25285 * @extends Roo.bootstrap.Component
25286 * Bootstrap MessageBar class
25287 * @cfg {String} html contents of the MessageBar
25288 * @cfg {String} weight (info | success | warning | danger) default info
25289 * @cfg {String} beforeClass insert the bar before the given class
25290 * @cfg {Boolean} closable (true | false) default false
25291 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25294 * Create a new Element
25295 * @param {Object} config The config object
25298 Roo.bootstrap.MessageBar = function(config){
25299 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25302 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25308 beforeClass: 'bootstrap-sticky-wrap',
25310 getAutoCreate : function(){
25314 cls: 'alert alert-dismissable alert-' + this.weight,
25319 html: this.html || ''
25325 cfg.cls += ' alert-messages-fixed';
25339 onRender : function(ct, position)
25341 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25344 var cfg = Roo.apply({}, this.getAutoCreate());
25348 cfg.cls += ' ' + this.cls;
25351 cfg.style = this.style;
25353 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25355 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25358 this.el.select('>button.close').on('click', this.hide, this);
25364 if (!this.rendered) {
25370 this.fireEvent('show', this);
25376 if (!this.rendered) {
25382 this.fireEvent('hide', this);
25385 update : function()
25387 // var e = this.el.dom.firstChild;
25389 // if(this.closable){
25390 // e = e.nextSibling;
25393 // e.data = this.html || '';
25395 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25411 * @class Roo.bootstrap.Graph
25412 * @extends Roo.bootstrap.Component
25413 * Bootstrap Graph class
25417 @cfg {String} graphtype bar | vbar | pie
25418 @cfg {number} g_x coodinator | centre x (pie)
25419 @cfg {number} g_y coodinator | centre y (pie)
25420 @cfg {number} g_r radius (pie)
25421 @cfg {number} g_height height of the chart (respected by all elements in the set)
25422 @cfg {number} g_width width of the chart (respected by all elements in the set)
25423 @cfg {Object} title The title of the chart
25426 -opts (object) options for the chart
25428 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25429 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25431 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.
25432 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25434 o stretch (boolean)
25436 -opts (object) options for the pie
25439 o startAngle (number)
25440 o endAngle (number)
25444 * Create a new Input
25445 * @param {Object} config The config object
25448 Roo.bootstrap.Graph = function(config){
25449 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25455 * The img click event for the img.
25456 * @param {Roo.EventObject} e
25462 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25473 //g_colors: this.colors,
25480 getAutoCreate : function(){
25491 onRender : function(ct,position){
25494 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25496 if (typeof(Raphael) == 'undefined') {
25497 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25501 this.raphael = Raphael(this.el.dom);
25503 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25504 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25505 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25506 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25508 r.text(160, 10, "Single Series Chart").attr(txtattr);
25509 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25510 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25511 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25513 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25514 r.barchart(330, 10, 300, 220, data1);
25515 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25516 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25519 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25520 // r.barchart(30, 30, 560, 250, xdata, {
25521 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25522 // axis : "0 0 1 1",
25523 // axisxlabels : xdata
25524 // //yvalues : cols,
25527 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25529 // this.load(null,xdata,{
25530 // axis : "0 0 1 1",
25531 // axisxlabels : xdata
25536 load : function(graphtype,xdata,opts)
25538 this.raphael.clear();
25540 graphtype = this.graphtype;
25545 var r = this.raphael,
25546 fin = function () {
25547 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25549 fout = function () {
25550 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25552 pfin = function() {
25553 this.sector.stop();
25554 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25557 this.label[0].stop();
25558 this.label[0].attr({ r: 7.5 });
25559 this.label[1].attr({ "font-weight": 800 });
25562 pfout = function() {
25563 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25566 this.label[0].animate({ r: 5 }, 500, "bounce");
25567 this.label[1].attr({ "font-weight": 400 });
25573 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25576 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25579 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25580 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25582 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25589 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25594 setTitle: function(o)
25599 initEvents: function() {
25602 this.el.on('click', this.onClick, this);
25606 onClick : function(e)
25608 Roo.log('img onclick');
25609 this.fireEvent('click', this, e);
25621 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25624 * @class Roo.bootstrap.dash.NumberBox
25625 * @extends Roo.bootstrap.Component
25626 * Bootstrap NumberBox class
25627 * @cfg {String} headline Box headline
25628 * @cfg {String} content Box content
25629 * @cfg {String} icon Box icon
25630 * @cfg {String} footer Footer text
25631 * @cfg {String} fhref Footer href
25634 * Create a new NumberBox
25635 * @param {Object} config The config object
25639 Roo.bootstrap.dash.NumberBox = function(config){
25640 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25644 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25653 getAutoCreate : function(){
25657 cls : 'small-box ',
25665 cls : 'roo-headline',
25666 html : this.headline
25670 cls : 'roo-content',
25671 html : this.content
25685 cls : 'ion ' + this.icon
25694 cls : 'small-box-footer',
25695 href : this.fhref || '#',
25699 cfg.cn.push(footer);
25706 onRender : function(ct,position){
25707 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25714 setHeadline: function (value)
25716 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25719 setFooter: function (value, href)
25721 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25724 this.el.select('a.small-box-footer',true).first().attr('href', href);
25729 setContent: function (value)
25731 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25734 initEvents: function()
25748 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25751 * @class Roo.bootstrap.dash.TabBox
25752 * @extends Roo.bootstrap.Component
25753 * Bootstrap TabBox class
25754 * @cfg {String} title Title of the TabBox
25755 * @cfg {String} icon Icon of the TabBox
25756 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25757 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25760 * Create a new TabBox
25761 * @param {Object} config The config object
25765 Roo.bootstrap.dash.TabBox = function(config){
25766 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25771 * When a pane is added
25772 * @param {Roo.bootstrap.dash.TabPane} pane
25776 * @event activatepane
25777 * When a pane is activated
25778 * @param {Roo.bootstrap.dash.TabPane} pane
25780 "activatepane" : true
25788 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25793 tabScrollable : false,
25795 getChildContainer : function()
25797 return this.el.select('.tab-content', true).first();
25800 getAutoCreate : function(){
25804 cls: 'pull-left header',
25812 cls: 'fa ' + this.icon
25818 cls: 'nav nav-tabs pull-right',
25824 if(this.tabScrollable){
25831 cls: 'nav nav-tabs pull-right',
25842 cls: 'nav-tabs-custom',
25847 cls: 'tab-content no-padding',
25855 initEvents : function()
25857 //Roo.log('add add pane handler');
25858 this.on('addpane', this.onAddPane, this);
25861 * Updates the box title
25862 * @param {String} html to set the title to.
25864 setTitle : function(value)
25866 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25868 onAddPane : function(pane)
25870 this.panes.push(pane);
25871 //Roo.log('addpane');
25873 // tabs are rendere left to right..
25874 if(!this.showtabs){
25878 var ctr = this.el.select('.nav-tabs', true).first();
25881 var existing = ctr.select('.nav-tab',true);
25882 var qty = existing.getCount();;
25885 var tab = ctr.createChild({
25887 cls : 'nav-tab' + (qty ? '' : ' active'),
25895 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25898 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25900 pane.el.addClass('active');
25905 onTabClick : function(ev,un,ob,pane)
25907 //Roo.log('tab - prev default');
25908 ev.preventDefault();
25911 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25912 pane.tab.addClass('active');
25913 //Roo.log(pane.title);
25914 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25915 // technically we should have a deactivate event.. but maybe add later.
25916 // and it should not de-activate the selected tab...
25917 this.fireEvent('activatepane', pane);
25918 pane.el.addClass('active');
25919 pane.fireEvent('activate');
25924 getActivePane : function()
25927 Roo.each(this.panes, function(p) {
25928 if(p.el.hasClass('active')){
25949 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25951 * @class Roo.bootstrap.TabPane
25952 * @extends Roo.bootstrap.Component
25953 * Bootstrap TabPane class
25954 * @cfg {Boolean} active (false | true) Default false
25955 * @cfg {String} title title of panel
25959 * Create a new TabPane
25960 * @param {Object} config The config object
25963 Roo.bootstrap.dash.TabPane = function(config){
25964 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25970 * When a pane is activated
25971 * @param {Roo.bootstrap.dash.TabPane} pane
25978 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25983 // the tabBox that this is attached to.
25986 getAutoCreate : function()
25994 cfg.cls += ' active';
25999 initEvents : function()
26001 //Roo.log('trigger add pane handler');
26002 this.parent().fireEvent('addpane', this)
26006 * Updates the tab title
26007 * @param {String} html to set the title to.
26009 setTitle: function(str)
26015 this.tab.select('a', true).first().dom.innerHTML = str;
26032 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26035 * @class Roo.bootstrap.menu.Menu
26036 * @extends Roo.bootstrap.Component
26037 * Bootstrap Menu class - container for Menu
26038 * @cfg {String} html Text of the menu
26039 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
26040 * @cfg {String} icon Font awesome icon
26041 * @cfg {String} pos Menu align to (top | bottom) default bottom
26045 * Create a new Menu
26046 * @param {Object} config The config object
26050 Roo.bootstrap.menu.Menu = function(config){
26051 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26055 * @event beforeshow
26056 * Fires before this menu is displayed
26057 * @param {Roo.bootstrap.menu.Menu} this
26061 * @event beforehide
26062 * Fires before this menu is hidden
26063 * @param {Roo.bootstrap.menu.Menu} this
26068 * Fires after this menu is displayed
26069 * @param {Roo.bootstrap.menu.Menu} this
26074 * Fires after this menu is hidden
26075 * @param {Roo.bootstrap.menu.Menu} this
26080 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26081 * @param {Roo.bootstrap.menu.Menu} this
26082 * @param {Roo.EventObject} e
26089 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26093 weight : 'default',
26098 getChildContainer : function() {
26099 if(this.isSubMenu){
26103 return this.el.select('ul.dropdown-menu', true).first();
26106 getAutoCreate : function()
26111 cls : 'roo-menu-text',
26119 cls : 'fa ' + this.icon
26130 cls : 'dropdown-button btn btn-' + this.weight,
26135 cls : 'dropdown-toggle btn btn-' + this.weight,
26145 cls : 'dropdown-menu'
26151 if(this.pos == 'top'){
26152 cfg.cls += ' dropup';
26155 if(this.isSubMenu){
26158 cls : 'dropdown-menu'
26165 onRender : function(ct, position)
26167 this.isSubMenu = ct.hasClass('dropdown-submenu');
26169 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26172 initEvents : function()
26174 if(this.isSubMenu){
26178 this.hidden = true;
26180 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26181 this.triggerEl.on('click', this.onTriggerPress, this);
26183 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26184 this.buttonEl.on('click', this.onClick, this);
26190 if(this.isSubMenu){
26194 return this.el.select('ul.dropdown-menu', true).first();
26197 onClick : function(e)
26199 this.fireEvent("click", this, e);
26202 onTriggerPress : function(e)
26204 if (this.isVisible()) {
26211 isVisible : function(){
26212 return !this.hidden;
26217 this.fireEvent("beforeshow", this);
26219 this.hidden = false;
26220 this.el.addClass('open');
26222 Roo.get(document).on("mouseup", this.onMouseUp, this);
26224 this.fireEvent("show", this);
26231 this.fireEvent("beforehide", this);
26233 this.hidden = true;
26234 this.el.removeClass('open');
26236 Roo.get(document).un("mouseup", this.onMouseUp);
26238 this.fireEvent("hide", this);
26241 onMouseUp : function()
26255 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26258 * @class Roo.bootstrap.menu.Item
26259 * @extends Roo.bootstrap.Component
26260 * Bootstrap MenuItem class
26261 * @cfg {Boolean} submenu (true | false) default false
26262 * @cfg {String} html text of the item
26263 * @cfg {String} href the link
26264 * @cfg {Boolean} disable (true | false) default false
26265 * @cfg {Boolean} preventDefault (true | false) default true
26266 * @cfg {String} icon Font awesome icon
26267 * @cfg {String} pos Submenu align to (left | right) default right
26271 * Create a new Item
26272 * @param {Object} config The config object
26276 Roo.bootstrap.menu.Item = function(config){
26277 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26281 * Fires when the mouse is hovering over this menu
26282 * @param {Roo.bootstrap.menu.Item} this
26283 * @param {Roo.EventObject} e
26288 * Fires when the mouse exits this menu
26289 * @param {Roo.bootstrap.menu.Item} this
26290 * @param {Roo.EventObject} e
26296 * The raw click event for the entire grid.
26297 * @param {Roo.EventObject} e
26303 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26308 preventDefault: true,
26313 getAutoCreate : function()
26318 cls : 'roo-menu-item-text',
26326 cls : 'fa ' + this.icon
26335 href : this.href || '#',
26342 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26346 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26348 if(this.pos == 'left'){
26349 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26356 initEvents : function()
26358 this.el.on('mouseover', this.onMouseOver, this);
26359 this.el.on('mouseout', this.onMouseOut, this);
26361 this.el.select('a', true).first().on('click', this.onClick, this);
26365 onClick : function(e)
26367 if(this.preventDefault){
26368 e.preventDefault();
26371 this.fireEvent("click", this, e);
26374 onMouseOver : function(e)
26376 if(this.submenu && this.pos == 'left'){
26377 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26380 this.fireEvent("mouseover", this, e);
26383 onMouseOut : function(e)
26385 this.fireEvent("mouseout", this, e);
26397 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26400 * @class Roo.bootstrap.menu.Separator
26401 * @extends Roo.bootstrap.Component
26402 * Bootstrap Separator class
26405 * Create a new Separator
26406 * @param {Object} config The config object
26410 Roo.bootstrap.menu.Separator = function(config){
26411 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26414 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26416 getAutoCreate : function(){
26437 * @class Roo.bootstrap.Tooltip
26438 * Bootstrap Tooltip class
26439 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26440 * to determine which dom element triggers the tooltip.
26442 * It needs to add support for additional attributes like tooltip-position
26445 * Create a new Toolti
26446 * @param {Object} config The config object
26449 Roo.bootstrap.Tooltip = function(config){
26450 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26452 this.alignment = Roo.bootstrap.Tooltip.alignment;
26454 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26455 this.alignment = config.alignment;
26460 Roo.apply(Roo.bootstrap.Tooltip, {
26462 * @function init initialize tooltip monitoring.
26466 currentTip : false,
26467 currentRegion : false,
26473 Roo.get(document).on('mouseover', this.enter ,this);
26474 Roo.get(document).on('mouseout', this.leave, this);
26477 this.currentTip = new Roo.bootstrap.Tooltip();
26480 enter : function(ev)
26482 var dom = ev.getTarget();
26484 //Roo.log(['enter',dom]);
26485 var el = Roo.fly(dom);
26486 if (this.currentEl) {
26488 //Roo.log(this.currentEl);
26489 //Roo.log(this.currentEl.contains(dom));
26490 if (this.currentEl == el) {
26493 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26499 if (this.currentTip.el) {
26500 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26504 if(!el || el.dom == document){
26510 // you can not look for children, as if el is the body.. then everythign is the child..
26511 if (!el.attr('tooltip')) { //
26512 if (!el.select("[tooltip]").elements.length) {
26515 // is the mouse over this child...?
26516 bindEl = el.select("[tooltip]").first();
26517 var xy = ev.getXY();
26518 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26519 //Roo.log("not in region.");
26522 //Roo.log("child element over..");
26525 this.currentEl = bindEl;
26526 this.currentTip.bind(bindEl);
26527 this.currentRegion = Roo.lib.Region.getRegion(dom);
26528 this.currentTip.enter();
26531 leave : function(ev)
26533 var dom = ev.getTarget();
26534 //Roo.log(['leave',dom]);
26535 if (!this.currentEl) {
26540 if (dom != this.currentEl.dom) {
26543 var xy = ev.getXY();
26544 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26547 // only activate leave if mouse cursor is outside... bounding box..
26552 if (this.currentTip) {
26553 this.currentTip.leave();
26555 //Roo.log('clear currentEl');
26556 this.currentEl = false;
26561 'left' : ['r-l', [-2,0], 'right'],
26562 'right' : ['l-r', [2,0], 'left'],
26563 'bottom' : ['t-b', [0,2], 'top'],
26564 'top' : [ 'b-t', [0,-2], 'bottom']
26570 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26575 delay : null, // can be { show : 300 , hide: 500}
26579 hoverState : null, //???
26581 placement : 'bottom',
26585 getAutoCreate : function(){
26592 cls : 'tooltip-arrow'
26595 cls : 'tooltip-inner'
26602 bind : function(el)
26608 enter : function () {
26610 if (this.timeout != null) {
26611 clearTimeout(this.timeout);
26614 this.hoverState = 'in';
26615 //Roo.log("enter - show");
26616 if (!this.delay || !this.delay.show) {
26621 this.timeout = setTimeout(function () {
26622 if (_t.hoverState == 'in') {
26625 }, this.delay.show);
26629 clearTimeout(this.timeout);
26631 this.hoverState = 'out';
26632 if (!this.delay || !this.delay.hide) {
26638 this.timeout = setTimeout(function () {
26639 //Roo.log("leave - timeout");
26641 if (_t.hoverState == 'out') {
26643 Roo.bootstrap.Tooltip.currentEl = false;
26648 show : function (msg)
26651 this.render(document.body);
26654 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26656 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26658 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26660 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26662 var placement = typeof this.placement == 'function' ?
26663 this.placement.call(this, this.el, on_el) :
26666 var autoToken = /\s?auto?\s?/i;
26667 var autoPlace = autoToken.test(placement);
26669 placement = placement.replace(autoToken, '') || 'top';
26673 //this.el.setXY([0,0]);
26675 //this.el.dom.style.display='block';
26677 //this.el.appendTo(on_el);
26679 var p = this.getPosition();
26680 var box = this.el.getBox();
26686 var align = this.alignment[placement];
26688 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26690 if(placement == 'top' || placement == 'bottom'){
26692 placement = 'right';
26695 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26696 placement = 'left';
26699 var scroll = Roo.select('body', true).first().getScroll();
26701 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26705 align = this.alignment[placement];
26708 this.el.alignTo(this.bindEl, align[0],align[1]);
26709 //var arrow = this.el.select('.arrow',true).first();
26710 //arrow.set(align[2],
26712 this.el.addClass(placement);
26714 this.el.addClass('in fade');
26716 this.hoverState = null;
26718 if (this.el.hasClass('fade')) {
26729 //this.el.setXY([0,0]);
26730 this.el.removeClass('in');
26746 * @class Roo.bootstrap.LocationPicker
26747 * @extends Roo.bootstrap.Component
26748 * Bootstrap LocationPicker class
26749 * @cfg {Number} latitude Position when init default 0
26750 * @cfg {Number} longitude Position when init default 0
26751 * @cfg {Number} zoom default 15
26752 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26753 * @cfg {Boolean} mapTypeControl default false
26754 * @cfg {Boolean} disableDoubleClickZoom default false
26755 * @cfg {Boolean} scrollwheel default true
26756 * @cfg {Boolean} streetViewControl default false
26757 * @cfg {Number} radius default 0
26758 * @cfg {String} locationName
26759 * @cfg {Boolean} draggable default true
26760 * @cfg {Boolean} enableAutocomplete default false
26761 * @cfg {Boolean} enableReverseGeocode default true
26762 * @cfg {String} markerTitle
26765 * Create a new LocationPicker
26766 * @param {Object} config The config object
26770 Roo.bootstrap.LocationPicker = function(config){
26772 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26777 * Fires when the picker initialized.
26778 * @param {Roo.bootstrap.LocationPicker} this
26779 * @param {Google Location} location
26783 * @event positionchanged
26784 * Fires when the picker position changed.
26785 * @param {Roo.bootstrap.LocationPicker} this
26786 * @param {Google Location} location
26788 positionchanged : true,
26791 * Fires when the map resize.
26792 * @param {Roo.bootstrap.LocationPicker} this
26797 * Fires when the map show.
26798 * @param {Roo.bootstrap.LocationPicker} this
26803 * Fires when the map hide.
26804 * @param {Roo.bootstrap.LocationPicker} this
26809 * Fires when click the map.
26810 * @param {Roo.bootstrap.LocationPicker} this
26811 * @param {Map event} e
26815 * @event mapRightClick
26816 * Fires when right click the map.
26817 * @param {Roo.bootstrap.LocationPicker} this
26818 * @param {Map event} e
26820 mapRightClick : true,
26822 * @event markerClick
26823 * Fires when click the marker.
26824 * @param {Roo.bootstrap.LocationPicker} this
26825 * @param {Map event} e
26827 markerClick : true,
26829 * @event markerRightClick
26830 * Fires when right click the marker.
26831 * @param {Roo.bootstrap.LocationPicker} this
26832 * @param {Map event} e
26834 markerRightClick : true,
26836 * @event OverlayViewDraw
26837 * Fires when OverlayView Draw
26838 * @param {Roo.bootstrap.LocationPicker} this
26840 OverlayViewDraw : true,
26842 * @event OverlayViewOnAdd
26843 * Fires when OverlayView Draw
26844 * @param {Roo.bootstrap.LocationPicker} this
26846 OverlayViewOnAdd : true,
26848 * @event OverlayViewOnRemove
26849 * Fires when OverlayView Draw
26850 * @param {Roo.bootstrap.LocationPicker} this
26852 OverlayViewOnRemove : true,
26854 * @event OverlayViewShow
26855 * Fires when OverlayView Draw
26856 * @param {Roo.bootstrap.LocationPicker} this
26857 * @param {Pixel} cpx
26859 OverlayViewShow : true,
26861 * @event OverlayViewHide
26862 * Fires when OverlayView Draw
26863 * @param {Roo.bootstrap.LocationPicker} this
26865 OverlayViewHide : true,
26867 * @event loadexception
26868 * Fires when load google lib failed.
26869 * @param {Roo.bootstrap.LocationPicker} this
26871 loadexception : true
26876 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26878 gMapContext: false,
26884 mapTypeControl: false,
26885 disableDoubleClickZoom: false,
26887 streetViewControl: false,
26891 enableAutocomplete: false,
26892 enableReverseGeocode: true,
26895 getAutoCreate: function()
26900 cls: 'roo-location-picker'
26906 initEvents: function(ct, position)
26908 if(!this.el.getWidth() || this.isApplied()){
26912 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26917 initial: function()
26919 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26920 this.fireEvent('loadexception', this);
26924 if(!this.mapTypeId){
26925 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26928 this.gMapContext = this.GMapContext();
26930 this.initOverlayView();
26932 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26936 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26937 _this.setPosition(_this.gMapContext.marker.position);
26940 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26941 _this.fireEvent('mapClick', this, event);
26945 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26946 _this.fireEvent('mapRightClick', this, event);
26950 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26951 _this.fireEvent('markerClick', this, event);
26955 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26956 _this.fireEvent('markerRightClick', this, event);
26960 this.setPosition(this.gMapContext.location);
26962 this.fireEvent('initial', this, this.gMapContext.location);
26965 initOverlayView: function()
26969 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26973 _this.fireEvent('OverlayViewDraw', _this);
26978 _this.fireEvent('OverlayViewOnAdd', _this);
26981 onRemove: function()
26983 _this.fireEvent('OverlayViewOnRemove', _this);
26986 show: function(cpx)
26988 _this.fireEvent('OverlayViewShow', _this, cpx);
26993 _this.fireEvent('OverlayViewHide', _this);
26999 fromLatLngToContainerPixel: function(event)
27001 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
27004 isApplied: function()
27006 return this.getGmapContext() == false ? false : true;
27009 getGmapContext: function()
27011 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
27014 GMapContext: function()
27016 var position = new google.maps.LatLng(this.latitude, this.longitude);
27018 var _map = new google.maps.Map(this.el.dom, {
27021 mapTypeId: this.mapTypeId,
27022 mapTypeControl: this.mapTypeControl,
27023 disableDoubleClickZoom: this.disableDoubleClickZoom,
27024 scrollwheel: this.scrollwheel,
27025 streetViewControl: this.streetViewControl,
27026 locationName: this.locationName,
27027 draggable: this.draggable,
27028 enableAutocomplete: this.enableAutocomplete,
27029 enableReverseGeocode: this.enableReverseGeocode
27032 var _marker = new google.maps.Marker({
27033 position: position,
27035 title: this.markerTitle,
27036 draggable: this.draggable
27043 location: position,
27044 radius: this.radius,
27045 locationName: this.locationName,
27046 addressComponents: {
27047 formatted_address: null,
27048 addressLine1: null,
27049 addressLine2: null,
27051 streetNumber: null,
27055 stateOrProvince: null
27058 domContainer: this.el.dom,
27059 geodecoder: new google.maps.Geocoder()
27063 drawCircle: function(center, radius, options)
27065 if (this.gMapContext.circle != null) {
27066 this.gMapContext.circle.setMap(null);
27070 options = Roo.apply({}, options, {
27071 strokeColor: "#0000FF",
27072 strokeOpacity: .35,
27074 fillColor: "#0000FF",
27078 options.map = this.gMapContext.map;
27079 options.radius = radius;
27080 options.center = center;
27081 this.gMapContext.circle = new google.maps.Circle(options);
27082 return this.gMapContext.circle;
27088 setPosition: function(location)
27090 this.gMapContext.location = location;
27091 this.gMapContext.marker.setPosition(location);
27092 this.gMapContext.map.panTo(location);
27093 this.drawCircle(location, this.gMapContext.radius, {});
27097 if (this.gMapContext.settings.enableReverseGeocode) {
27098 this.gMapContext.geodecoder.geocode({
27099 latLng: this.gMapContext.location
27100 }, function(results, status) {
27102 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27103 _this.gMapContext.locationName = results[0].formatted_address;
27104 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27106 _this.fireEvent('positionchanged', this, location);
27113 this.fireEvent('positionchanged', this, location);
27118 google.maps.event.trigger(this.gMapContext.map, "resize");
27120 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27122 this.fireEvent('resize', this);
27125 setPositionByLatLng: function(latitude, longitude)
27127 this.setPosition(new google.maps.LatLng(latitude, longitude));
27130 getCurrentPosition: function()
27133 latitude: this.gMapContext.location.lat(),
27134 longitude: this.gMapContext.location.lng()
27138 getAddressName: function()
27140 return this.gMapContext.locationName;
27143 getAddressComponents: function()
27145 return this.gMapContext.addressComponents;
27148 address_component_from_google_geocode: function(address_components)
27152 for (var i = 0; i < address_components.length; i++) {
27153 var component = address_components[i];
27154 if (component.types.indexOf("postal_code") >= 0) {
27155 result.postalCode = component.short_name;
27156 } else if (component.types.indexOf("street_number") >= 0) {
27157 result.streetNumber = component.short_name;
27158 } else if (component.types.indexOf("route") >= 0) {
27159 result.streetName = component.short_name;
27160 } else if (component.types.indexOf("neighborhood") >= 0) {
27161 result.city = component.short_name;
27162 } else if (component.types.indexOf("locality") >= 0) {
27163 result.city = component.short_name;
27164 } else if (component.types.indexOf("sublocality") >= 0) {
27165 result.district = component.short_name;
27166 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27167 result.stateOrProvince = component.short_name;
27168 } else if (component.types.indexOf("country") >= 0) {
27169 result.country = component.short_name;
27173 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27174 result.addressLine2 = "";
27178 setZoomLevel: function(zoom)
27180 this.gMapContext.map.setZoom(zoom);
27193 this.fireEvent('show', this);
27204 this.fireEvent('hide', this);
27209 Roo.apply(Roo.bootstrap.LocationPicker, {
27211 OverlayView : function(map, options)
27213 options = options || {};
27220 * @class Roo.bootstrap.Alert
27221 * @extends Roo.bootstrap.Component
27222 * Bootstrap Alert class - shows an alert area box
27224 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
27225 Enter a valid email address
27228 * @cfg {String} title The title of alert
27229 * @cfg {String} html The content of alert
27230 * @cfg {String} weight ( success | info | warning | danger )
27231 * @cfg {String} faicon font-awesomeicon
27234 * Create a new alert
27235 * @param {Object} config The config object
27239 Roo.bootstrap.Alert = function(config){
27240 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27244 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27251 getAutoCreate : function()
27260 cls : 'roo-alert-icon'
27265 cls : 'roo-alert-title',
27270 cls : 'roo-alert-text',
27277 cfg.cn[0].cls += ' fa ' + this.faicon;
27281 cfg.cls += ' alert-' + this.weight;
27287 initEvents: function()
27289 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27292 setTitle : function(str)
27294 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27297 setText : function(str)
27299 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27302 setWeight : function(weight)
27305 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27308 this.weight = weight;
27310 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27313 setIcon : function(icon)
27316 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27319 this.faicon = icon;
27321 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27342 * @class Roo.bootstrap.UploadCropbox
27343 * @extends Roo.bootstrap.Component
27344 * Bootstrap UploadCropbox class
27345 * @cfg {String} emptyText show when image has been loaded
27346 * @cfg {String} rotateNotify show when image too small to rotate
27347 * @cfg {Number} errorTimeout default 3000
27348 * @cfg {Number} minWidth default 300
27349 * @cfg {Number} minHeight default 300
27350 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27351 * @cfg {Boolean} isDocument (true|false) default false
27352 * @cfg {String} url action url
27353 * @cfg {String} paramName default 'imageUpload'
27354 * @cfg {String} method default POST
27355 * @cfg {Boolean} loadMask (true|false) default true
27356 * @cfg {Boolean} loadingText default 'Loading...'
27359 * Create a new UploadCropbox
27360 * @param {Object} config The config object
27363 Roo.bootstrap.UploadCropbox = function(config){
27364 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27368 * @event beforeselectfile
27369 * Fire before select file
27370 * @param {Roo.bootstrap.UploadCropbox} this
27372 "beforeselectfile" : true,
27375 * Fire after initEvent
27376 * @param {Roo.bootstrap.UploadCropbox} this
27381 * Fire after initEvent
27382 * @param {Roo.bootstrap.UploadCropbox} this
27383 * @param {String} data
27388 * Fire when preparing the file data
27389 * @param {Roo.bootstrap.UploadCropbox} this
27390 * @param {Object} file
27395 * Fire when get exception
27396 * @param {Roo.bootstrap.UploadCropbox} this
27397 * @param {XMLHttpRequest} xhr
27399 "exception" : true,
27401 * @event beforeloadcanvas
27402 * Fire before load the canvas
27403 * @param {Roo.bootstrap.UploadCropbox} this
27404 * @param {String} src
27406 "beforeloadcanvas" : true,
27409 * Fire when trash image
27410 * @param {Roo.bootstrap.UploadCropbox} this
27415 * Fire when download the image
27416 * @param {Roo.bootstrap.UploadCropbox} this
27420 * @event footerbuttonclick
27421 * Fire when footerbuttonclick
27422 * @param {Roo.bootstrap.UploadCropbox} this
27423 * @param {String} type
27425 "footerbuttonclick" : true,
27429 * @param {Roo.bootstrap.UploadCropbox} this
27434 * Fire when rotate the image
27435 * @param {Roo.bootstrap.UploadCropbox} this
27436 * @param {String} pos
27441 * Fire when inspect the file
27442 * @param {Roo.bootstrap.UploadCropbox} this
27443 * @param {Object} file
27448 * Fire when xhr upload the file
27449 * @param {Roo.bootstrap.UploadCropbox} this
27450 * @param {Object} data
27455 * Fire when arrange the file data
27456 * @param {Roo.bootstrap.UploadCropbox} this
27457 * @param {Object} formData
27462 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27465 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27467 emptyText : 'Click to upload image',
27468 rotateNotify : 'Image is too small to rotate',
27469 errorTimeout : 3000,
27483 cropType : 'image/jpeg',
27485 canvasLoaded : false,
27486 isDocument : false,
27488 paramName : 'imageUpload',
27490 loadingText : 'Loading...',
27493 getAutoCreate : function()
27497 cls : 'roo-upload-cropbox',
27501 cls : 'roo-upload-cropbox-selector',
27506 cls : 'roo-upload-cropbox-body',
27507 style : 'cursor:pointer',
27511 cls : 'roo-upload-cropbox-preview'
27515 cls : 'roo-upload-cropbox-thumb'
27519 cls : 'roo-upload-cropbox-empty-notify',
27520 html : this.emptyText
27524 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27525 html : this.rotateNotify
27531 cls : 'roo-upload-cropbox-footer',
27534 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27544 onRender : function(ct, position)
27546 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27548 if (this.buttons.length) {
27550 Roo.each(this.buttons, function(bb) {
27552 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27554 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27560 this.maskEl = this.el;
27564 initEvents : function()
27566 this.urlAPI = (window.createObjectURL && window) ||
27567 (window.URL && URL.revokeObjectURL && URL) ||
27568 (window.webkitURL && webkitURL);
27570 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27571 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27573 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27574 this.selectorEl.hide();
27576 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27577 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27579 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27580 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27581 this.thumbEl.hide();
27583 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27584 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27586 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27587 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27588 this.errorEl.hide();
27590 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27591 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27592 this.footerEl.hide();
27594 this.setThumbBoxSize();
27600 this.fireEvent('initial', this);
27607 window.addEventListener("resize", function() { _this.resize(); } );
27609 this.bodyEl.on('click', this.beforeSelectFile, this);
27612 this.bodyEl.on('touchstart', this.onTouchStart, this);
27613 this.bodyEl.on('touchmove', this.onTouchMove, this);
27614 this.bodyEl.on('touchend', this.onTouchEnd, this);
27618 this.bodyEl.on('mousedown', this.onMouseDown, this);
27619 this.bodyEl.on('mousemove', this.onMouseMove, this);
27620 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27621 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27622 Roo.get(document).on('mouseup', this.onMouseUp, this);
27625 this.selectorEl.on('change', this.onFileSelected, this);
27631 this.baseScale = 1;
27633 this.baseRotate = 1;
27634 this.dragable = false;
27635 this.pinching = false;
27638 this.cropData = false;
27639 this.notifyEl.dom.innerHTML = this.emptyText;
27641 this.selectorEl.dom.value = '';
27645 resize : function()
27647 if(this.fireEvent('resize', this) != false){
27648 this.setThumbBoxPosition();
27649 this.setCanvasPosition();
27653 onFooterButtonClick : function(e, el, o, type)
27656 case 'rotate-left' :
27657 this.onRotateLeft(e);
27659 case 'rotate-right' :
27660 this.onRotateRight(e);
27663 this.beforeSelectFile(e);
27678 this.fireEvent('footerbuttonclick', this, type);
27681 beforeSelectFile : function(e)
27683 e.preventDefault();
27685 if(this.fireEvent('beforeselectfile', this) != false){
27686 this.selectorEl.dom.click();
27690 onFileSelected : function(e)
27692 e.preventDefault();
27694 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27698 var file = this.selectorEl.dom.files[0];
27700 if(this.fireEvent('inspect', this, file) != false){
27701 this.prepare(file);
27706 trash : function(e)
27708 this.fireEvent('trash', this);
27711 download : function(e)
27713 this.fireEvent('download', this);
27716 loadCanvas : function(src)
27718 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27722 this.imageEl = document.createElement('img');
27726 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27728 this.imageEl.src = src;
27732 onLoadCanvas : function()
27734 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27735 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27737 this.bodyEl.un('click', this.beforeSelectFile, this);
27739 this.notifyEl.hide();
27740 this.thumbEl.show();
27741 this.footerEl.show();
27743 this.baseRotateLevel();
27745 if(this.isDocument){
27746 this.setThumbBoxSize();
27749 this.setThumbBoxPosition();
27751 this.baseScaleLevel();
27757 this.canvasLoaded = true;
27760 this.maskEl.unmask();
27765 setCanvasPosition : function()
27767 if(!this.canvasEl){
27771 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27772 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27774 this.previewEl.setLeft(pw);
27775 this.previewEl.setTop(ph);
27779 onMouseDown : function(e)
27783 this.dragable = true;
27784 this.pinching = false;
27786 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27787 this.dragable = false;
27791 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27792 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27796 onMouseMove : function(e)
27800 if(!this.canvasLoaded){
27804 if (!this.dragable){
27808 var minX = Math.ceil(this.thumbEl.getLeft(true));
27809 var minY = Math.ceil(this.thumbEl.getTop(true));
27811 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27812 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27814 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27815 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27817 x = x - this.mouseX;
27818 y = y - this.mouseY;
27820 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27821 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27823 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27824 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27826 this.previewEl.setLeft(bgX);
27827 this.previewEl.setTop(bgY);
27829 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27830 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27833 onMouseUp : function(e)
27837 this.dragable = false;
27840 onMouseWheel : function(e)
27844 this.startScale = this.scale;
27846 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27848 if(!this.zoomable()){
27849 this.scale = this.startScale;
27858 zoomable : function()
27860 var minScale = this.thumbEl.getWidth() / this.minWidth;
27862 if(this.minWidth < this.minHeight){
27863 minScale = this.thumbEl.getHeight() / this.minHeight;
27866 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27867 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27871 (this.rotate == 0 || this.rotate == 180) &&
27873 width > this.imageEl.OriginWidth ||
27874 height > this.imageEl.OriginHeight ||
27875 (width < this.minWidth && height < this.minHeight)
27883 (this.rotate == 90 || this.rotate == 270) &&
27885 width > this.imageEl.OriginWidth ||
27886 height > this.imageEl.OriginHeight ||
27887 (width < this.minHeight && height < this.minWidth)
27894 !this.isDocument &&
27895 (this.rotate == 0 || this.rotate == 180) &&
27897 width < this.minWidth ||
27898 width > this.imageEl.OriginWidth ||
27899 height < this.minHeight ||
27900 height > this.imageEl.OriginHeight
27907 !this.isDocument &&
27908 (this.rotate == 90 || this.rotate == 270) &&
27910 width < this.minHeight ||
27911 width > this.imageEl.OriginWidth ||
27912 height < this.minWidth ||
27913 height > this.imageEl.OriginHeight
27923 onRotateLeft : function(e)
27925 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27927 var minScale = this.thumbEl.getWidth() / this.minWidth;
27929 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27930 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27932 this.startScale = this.scale;
27934 while (this.getScaleLevel() < minScale){
27936 this.scale = this.scale + 1;
27938 if(!this.zoomable()){
27943 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27944 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27949 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27956 this.scale = this.startScale;
27958 this.onRotateFail();
27963 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27965 if(this.isDocument){
27966 this.setThumbBoxSize();
27967 this.setThumbBoxPosition();
27968 this.setCanvasPosition();
27973 this.fireEvent('rotate', this, 'left');
27977 onRotateRight : function(e)
27979 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27981 var minScale = this.thumbEl.getWidth() / this.minWidth;
27983 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27984 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27986 this.startScale = this.scale;
27988 while (this.getScaleLevel() < minScale){
27990 this.scale = this.scale + 1;
27992 if(!this.zoomable()){
27997 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27998 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28003 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28010 this.scale = this.startScale;
28012 this.onRotateFail();
28017 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28019 if(this.isDocument){
28020 this.setThumbBoxSize();
28021 this.setThumbBoxPosition();
28022 this.setCanvasPosition();
28027 this.fireEvent('rotate', this, 'right');
28030 onRotateFail : function()
28032 this.errorEl.show(true);
28036 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
28041 this.previewEl.dom.innerHTML = '';
28043 var canvasEl = document.createElement("canvas");
28045 var contextEl = canvasEl.getContext("2d");
28047 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28048 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28049 var center = this.imageEl.OriginWidth / 2;
28051 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28052 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28053 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28054 center = this.imageEl.OriginHeight / 2;
28057 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28059 contextEl.translate(center, center);
28060 contextEl.rotate(this.rotate * Math.PI / 180);
28062 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28064 this.canvasEl = document.createElement("canvas");
28066 this.contextEl = this.canvasEl.getContext("2d");
28068 switch (this.rotate) {
28071 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28072 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28074 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28079 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28080 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28082 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28083 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);
28087 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28092 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28093 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28095 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28096 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);
28100 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);
28105 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28106 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28108 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28109 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28113 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);
28120 this.previewEl.appendChild(this.canvasEl);
28122 this.setCanvasPosition();
28127 if(!this.canvasLoaded){
28131 var imageCanvas = document.createElement("canvas");
28133 var imageContext = imageCanvas.getContext("2d");
28135 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28136 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28138 var center = imageCanvas.width / 2;
28140 imageContext.translate(center, center);
28142 imageContext.rotate(this.rotate * Math.PI / 180);
28144 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28146 var canvas = document.createElement("canvas");
28148 var context = canvas.getContext("2d");
28150 canvas.width = this.minWidth;
28151 canvas.height = this.minHeight;
28153 switch (this.rotate) {
28156 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28157 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28159 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28160 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28162 var targetWidth = this.minWidth - 2 * x;
28163 var targetHeight = this.minHeight - 2 * y;
28167 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28168 scale = targetWidth / width;
28171 if(x > 0 && y == 0){
28172 scale = targetHeight / height;
28175 if(x > 0 && y > 0){
28176 scale = targetWidth / width;
28178 if(width < height){
28179 scale = targetHeight / height;
28183 context.scale(scale, scale);
28185 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28186 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28188 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28189 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28191 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28196 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28197 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28199 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28200 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28202 var targetWidth = this.minWidth - 2 * x;
28203 var targetHeight = this.minHeight - 2 * y;
28207 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28208 scale = targetWidth / width;
28211 if(x > 0 && y == 0){
28212 scale = targetHeight / height;
28215 if(x > 0 && y > 0){
28216 scale = targetWidth / width;
28218 if(width < height){
28219 scale = targetHeight / height;
28223 context.scale(scale, scale);
28225 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28226 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28228 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28229 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28231 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28233 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28238 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28239 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28241 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28242 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28244 var targetWidth = this.minWidth - 2 * x;
28245 var targetHeight = this.minHeight - 2 * y;
28249 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28250 scale = targetWidth / width;
28253 if(x > 0 && y == 0){
28254 scale = targetHeight / height;
28257 if(x > 0 && y > 0){
28258 scale = targetWidth / width;
28260 if(width < height){
28261 scale = targetHeight / height;
28265 context.scale(scale, scale);
28267 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28268 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28270 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28271 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28273 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28274 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28276 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28281 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28282 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28284 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28285 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28287 var targetWidth = this.minWidth - 2 * x;
28288 var targetHeight = this.minHeight - 2 * y;
28292 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28293 scale = targetWidth / width;
28296 if(x > 0 && y == 0){
28297 scale = targetHeight / height;
28300 if(x > 0 && y > 0){
28301 scale = targetWidth / width;
28303 if(width < height){
28304 scale = targetHeight / height;
28308 context.scale(scale, scale);
28310 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28311 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28313 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28314 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28316 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28318 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28325 this.cropData = canvas.toDataURL(this.cropType);
28327 if(this.fireEvent('crop', this, this.cropData) !== false){
28328 this.process(this.file, this.cropData);
28335 setThumbBoxSize : function()
28339 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28340 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28341 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28343 this.minWidth = width;
28344 this.minHeight = height;
28346 if(this.rotate == 90 || this.rotate == 270){
28347 this.minWidth = height;
28348 this.minHeight = width;
28353 width = Math.ceil(this.minWidth * height / this.minHeight);
28355 if(this.minWidth > this.minHeight){
28357 height = Math.ceil(this.minHeight * width / this.minWidth);
28360 this.thumbEl.setStyle({
28361 width : width + 'px',
28362 height : height + 'px'
28369 setThumbBoxPosition : function()
28371 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28372 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28374 this.thumbEl.setLeft(x);
28375 this.thumbEl.setTop(y);
28379 baseRotateLevel : function()
28381 this.baseRotate = 1;
28384 typeof(this.exif) != 'undefined' &&
28385 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28386 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28388 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28391 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28395 baseScaleLevel : function()
28399 if(this.isDocument){
28401 if(this.baseRotate == 6 || this.baseRotate == 8){
28403 height = this.thumbEl.getHeight();
28404 this.baseScale = height / this.imageEl.OriginWidth;
28406 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28407 width = this.thumbEl.getWidth();
28408 this.baseScale = width / 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;
28425 if(this.baseRotate == 6 || this.baseRotate == 8){
28427 width = this.thumbEl.getHeight();
28428 this.baseScale = width / this.imageEl.OriginHeight;
28430 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28431 height = this.thumbEl.getWidth();
28432 this.baseScale = height / this.imageEl.OriginHeight;
28435 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28436 height = this.thumbEl.getWidth();
28437 this.baseScale = height / this.imageEl.OriginHeight;
28439 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28440 width = this.thumbEl.getHeight();
28441 this.baseScale = width / this.imageEl.OriginWidth;
28448 width = this.thumbEl.getWidth();
28449 this.baseScale = width / this.imageEl.OriginWidth;
28451 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28452 height = this.thumbEl.getHeight();
28453 this.baseScale = height / this.imageEl.OriginHeight;
28456 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28458 height = this.thumbEl.getHeight();
28459 this.baseScale = height / this.imageEl.OriginHeight;
28461 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28462 width = this.thumbEl.getWidth();
28463 this.baseScale = width / this.imageEl.OriginWidth;
28471 getScaleLevel : function()
28473 return this.baseScale * Math.pow(1.1, this.scale);
28476 onTouchStart : function(e)
28478 if(!this.canvasLoaded){
28479 this.beforeSelectFile(e);
28483 var touches = e.browserEvent.touches;
28489 if(touches.length == 1){
28490 this.onMouseDown(e);
28494 if(touches.length != 2){
28500 for(var i = 0, finger; finger = touches[i]; i++){
28501 coords.push(finger.pageX, finger.pageY);
28504 var x = Math.pow(coords[0] - coords[2], 2);
28505 var y = Math.pow(coords[1] - coords[3], 2);
28507 this.startDistance = Math.sqrt(x + y);
28509 this.startScale = this.scale;
28511 this.pinching = true;
28512 this.dragable = false;
28516 onTouchMove : function(e)
28518 if(!this.pinching && !this.dragable){
28522 var touches = e.browserEvent.touches;
28529 this.onMouseMove(e);
28535 for(var i = 0, finger; finger = touches[i]; i++){
28536 coords.push(finger.pageX, finger.pageY);
28539 var x = Math.pow(coords[0] - coords[2], 2);
28540 var y = Math.pow(coords[1] - coords[3], 2);
28542 this.endDistance = Math.sqrt(x + y);
28544 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28546 if(!this.zoomable()){
28547 this.scale = this.startScale;
28555 onTouchEnd : function(e)
28557 this.pinching = false;
28558 this.dragable = false;
28562 process : function(file, crop)
28565 this.maskEl.mask(this.loadingText);
28568 this.xhr = new XMLHttpRequest();
28570 file.xhr = this.xhr;
28572 this.xhr.open(this.method, this.url, true);
28575 "Accept": "application/json",
28576 "Cache-Control": "no-cache",
28577 "X-Requested-With": "XMLHttpRequest"
28580 for (var headerName in headers) {
28581 var headerValue = headers[headerName];
28583 this.xhr.setRequestHeader(headerName, headerValue);
28589 this.xhr.onload = function()
28591 _this.xhrOnLoad(_this.xhr);
28594 this.xhr.onerror = function()
28596 _this.xhrOnError(_this.xhr);
28599 var formData = new FormData();
28601 formData.append('returnHTML', 'NO');
28604 formData.append('crop', crop);
28607 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28608 formData.append(this.paramName, file, file.name);
28611 if(typeof(file.filename) != 'undefined'){
28612 formData.append('filename', file.filename);
28615 if(typeof(file.mimetype) != 'undefined'){
28616 formData.append('mimetype', file.mimetype);
28619 if(this.fireEvent('arrange', this, formData) != false){
28620 this.xhr.send(formData);
28624 xhrOnLoad : function(xhr)
28627 this.maskEl.unmask();
28630 if (xhr.readyState !== 4) {
28631 this.fireEvent('exception', this, xhr);
28635 var response = Roo.decode(xhr.responseText);
28637 if(!response.success){
28638 this.fireEvent('exception', this, xhr);
28642 var response = Roo.decode(xhr.responseText);
28644 this.fireEvent('upload', this, response);
28648 xhrOnError : function()
28651 this.maskEl.unmask();
28654 Roo.log('xhr on error');
28656 var response = Roo.decode(xhr.responseText);
28662 prepare : function(file)
28665 this.maskEl.mask(this.loadingText);
28671 if(typeof(file) === 'string'){
28672 this.loadCanvas(file);
28676 if(!file || !this.urlAPI){
28681 this.cropType = file.type;
28685 if(this.fireEvent('prepare', this, this.file) != false){
28687 var reader = new FileReader();
28689 reader.onload = function (e) {
28690 if (e.target.error) {
28691 Roo.log(e.target.error);
28695 var buffer = e.target.result,
28696 dataView = new DataView(buffer),
28698 maxOffset = dataView.byteLength - 4,
28702 if (dataView.getUint16(0) === 0xffd8) {
28703 while (offset < maxOffset) {
28704 markerBytes = dataView.getUint16(offset);
28706 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28707 markerLength = dataView.getUint16(offset + 2) + 2;
28708 if (offset + markerLength > dataView.byteLength) {
28709 Roo.log('Invalid meta data: Invalid segment size.');
28713 if(markerBytes == 0xffe1){
28714 _this.parseExifData(
28721 offset += markerLength;
28731 var url = _this.urlAPI.createObjectURL(_this.file);
28733 _this.loadCanvas(url);
28738 reader.readAsArrayBuffer(this.file);
28744 parseExifData : function(dataView, offset, length)
28746 var tiffOffset = offset + 10,
28750 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28751 // No Exif data, might be XMP data instead
28755 // Check for the ASCII code for "Exif" (0x45786966):
28756 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28757 // No Exif data, might be XMP data instead
28760 if (tiffOffset + 8 > dataView.byteLength) {
28761 Roo.log('Invalid Exif data: Invalid segment size.');
28764 // Check for the two null bytes:
28765 if (dataView.getUint16(offset + 8) !== 0x0000) {
28766 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28769 // Check the byte alignment:
28770 switch (dataView.getUint16(tiffOffset)) {
28772 littleEndian = true;
28775 littleEndian = false;
28778 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28781 // Check for the TIFF tag marker (0x002A):
28782 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28783 Roo.log('Invalid Exif data: Missing TIFF marker.');
28786 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28787 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28789 this.parseExifTags(
28792 tiffOffset + dirOffset,
28797 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28802 if (dirOffset + 6 > dataView.byteLength) {
28803 Roo.log('Invalid Exif data: Invalid directory offset.');
28806 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28807 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28808 if (dirEndOffset + 4 > dataView.byteLength) {
28809 Roo.log('Invalid Exif data: Invalid directory size.');
28812 for (i = 0; i < tagsNumber; i += 1) {
28816 dirOffset + 2 + 12 * i, // tag offset
28820 // Return the offset to the next directory:
28821 return dataView.getUint32(dirEndOffset, littleEndian);
28824 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28826 var tag = dataView.getUint16(offset, littleEndian);
28828 this.exif[tag] = this.getExifValue(
28832 dataView.getUint16(offset + 2, littleEndian), // tag type
28833 dataView.getUint32(offset + 4, littleEndian), // tag length
28838 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28840 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28849 Roo.log('Invalid Exif data: Invalid tag type.');
28853 tagSize = tagType.size * length;
28854 // Determine if the value is contained in the dataOffset bytes,
28855 // or if the value at the dataOffset is a pointer to the actual data:
28856 dataOffset = tagSize > 4 ?
28857 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28858 if (dataOffset + tagSize > dataView.byteLength) {
28859 Roo.log('Invalid Exif data: Invalid data offset.');
28862 if (length === 1) {
28863 return tagType.getValue(dataView, dataOffset, littleEndian);
28866 for (i = 0; i < length; i += 1) {
28867 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28870 if (tagType.ascii) {
28872 // Concatenate the chars:
28873 for (i = 0; i < values.length; i += 1) {
28875 // Ignore the terminating NULL byte(s):
28876 if (c === '\u0000') {
28888 Roo.apply(Roo.bootstrap.UploadCropbox, {
28890 'Orientation': 0x0112
28894 1: 0, //'top-left',
28896 3: 180, //'bottom-right',
28897 // 4: 'bottom-left',
28899 6: 90, //'right-top',
28900 // 7: 'right-bottom',
28901 8: 270 //'left-bottom'
28905 // byte, 8-bit unsigned int:
28907 getValue: function (dataView, dataOffset) {
28908 return dataView.getUint8(dataOffset);
28912 // ascii, 8-bit byte:
28914 getValue: function (dataView, dataOffset) {
28915 return String.fromCharCode(dataView.getUint8(dataOffset));
28920 // short, 16 bit int:
28922 getValue: function (dataView, dataOffset, littleEndian) {
28923 return dataView.getUint16(dataOffset, littleEndian);
28927 // long, 32 bit int:
28929 getValue: function (dataView, dataOffset, littleEndian) {
28930 return dataView.getUint32(dataOffset, littleEndian);
28934 // rational = two long values, first is numerator, second is denominator:
28936 getValue: function (dataView, dataOffset, littleEndian) {
28937 return dataView.getUint32(dataOffset, littleEndian) /
28938 dataView.getUint32(dataOffset + 4, littleEndian);
28942 // slong, 32 bit signed int:
28944 getValue: function (dataView, dataOffset, littleEndian) {
28945 return dataView.getInt32(dataOffset, littleEndian);
28949 // srational, two slongs, first is numerator, second is denominator:
28951 getValue: function (dataView, dataOffset, littleEndian) {
28952 return dataView.getInt32(dataOffset, littleEndian) /
28953 dataView.getInt32(dataOffset + 4, littleEndian);
28963 cls : 'btn-group roo-upload-cropbox-rotate-left',
28964 action : 'rotate-left',
28968 cls : 'btn btn-default',
28969 html : '<i class="fa fa-undo"></i>'
28975 cls : 'btn-group roo-upload-cropbox-picture',
28976 action : 'picture',
28980 cls : 'btn btn-default',
28981 html : '<i class="fa fa-picture-o"></i>'
28987 cls : 'btn-group roo-upload-cropbox-rotate-right',
28988 action : 'rotate-right',
28992 cls : 'btn btn-default',
28993 html : '<i class="fa fa-repeat"></i>'
29001 cls : 'btn-group roo-upload-cropbox-rotate-left',
29002 action : 'rotate-left',
29006 cls : 'btn btn-default',
29007 html : '<i class="fa fa-undo"></i>'
29013 cls : 'btn-group roo-upload-cropbox-download',
29014 action : 'download',
29018 cls : 'btn btn-default',
29019 html : '<i class="fa fa-download"></i>'
29025 cls : 'btn-group roo-upload-cropbox-crop',
29030 cls : 'btn btn-default',
29031 html : '<i class="fa fa-crop"></i>'
29037 cls : 'btn-group roo-upload-cropbox-trash',
29042 cls : 'btn btn-default',
29043 html : '<i class="fa fa-trash"></i>'
29049 cls : 'btn-group roo-upload-cropbox-rotate-right',
29050 action : 'rotate-right',
29054 cls : 'btn btn-default',
29055 html : '<i class="fa fa-repeat"></i>'
29063 cls : 'btn-group roo-upload-cropbox-rotate-left',
29064 action : 'rotate-left',
29068 cls : 'btn btn-default',
29069 html : '<i class="fa fa-undo"></i>'
29075 cls : 'btn-group roo-upload-cropbox-rotate-right',
29076 action : 'rotate-right',
29080 cls : 'btn btn-default',
29081 html : '<i class="fa fa-repeat"></i>'
29094 * @class Roo.bootstrap.DocumentManager
29095 * @extends Roo.bootstrap.Component
29096 * Bootstrap DocumentManager class
29097 * @cfg {String} paramName default 'imageUpload'
29098 * @cfg {String} toolTipName default 'filename'
29099 * @cfg {String} method default POST
29100 * @cfg {String} url action url
29101 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29102 * @cfg {Boolean} multiple multiple upload default true
29103 * @cfg {Number} thumbSize default 300
29104 * @cfg {String} fieldLabel
29105 * @cfg {Number} labelWidth default 4
29106 * @cfg {String} labelAlign (left|top) default left
29107 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29108 * @cfg {Number} labellg set the width of label (1-12)
29109 * @cfg {Number} labelmd set the width of label (1-12)
29110 * @cfg {Number} labelsm set the width of label (1-12)
29111 * @cfg {Number} labelxs set the width of label (1-12)
29114 * Create a new DocumentManager
29115 * @param {Object} config The config object
29118 Roo.bootstrap.DocumentManager = function(config){
29119 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29122 this.delegates = [];
29127 * Fire when initial the DocumentManager
29128 * @param {Roo.bootstrap.DocumentManager} this
29133 * inspect selected file
29134 * @param {Roo.bootstrap.DocumentManager} this
29135 * @param {File} file
29140 * Fire when xhr load exception
29141 * @param {Roo.bootstrap.DocumentManager} this
29142 * @param {XMLHttpRequest} xhr
29144 "exception" : true,
29146 * @event afterupload
29147 * Fire when xhr load exception
29148 * @param {Roo.bootstrap.DocumentManager} this
29149 * @param {XMLHttpRequest} xhr
29151 "afterupload" : true,
29154 * prepare the form data
29155 * @param {Roo.bootstrap.DocumentManager} this
29156 * @param {Object} formData
29161 * Fire when remove the file
29162 * @param {Roo.bootstrap.DocumentManager} this
29163 * @param {Object} file
29168 * Fire after refresh the file
29169 * @param {Roo.bootstrap.DocumentManager} this
29174 * Fire after click the image
29175 * @param {Roo.bootstrap.DocumentManager} this
29176 * @param {Object} file
29181 * Fire when upload a image and editable set to true
29182 * @param {Roo.bootstrap.DocumentManager} this
29183 * @param {Object} file
29187 * @event beforeselectfile
29188 * Fire before select file
29189 * @param {Roo.bootstrap.DocumentManager} this
29191 "beforeselectfile" : true,
29194 * Fire before process file
29195 * @param {Roo.bootstrap.DocumentManager} this
29196 * @param {Object} file
29200 * @event previewrendered
29201 * Fire when preview rendered
29202 * @param {Roo.bootstrap.DocumentManager} this
29203 * @param {Object} file
29205 "previewrendered" : true,
29208 "previewResize" : true
29213 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29222 paramName : 'imageUpload',
29223 toolTipName : 'filename',
29226 labelAlign : 'left',
29236 getAutoCreate : function()
29238 var managerWidget = {
29240 cls : 'roo-document-manager',
29244 cls : 'roo-document-manager-selector',
29249 cls : 'roo-document-manager-uploader',
29253 cls : 'roo-document-manager-upload-btn',
29254 html : '<i class="fa fa-plus"></i>'
29265 cls : 'column col-md-12',
29270 if(this.fieldLabel.length){
29275 cls : 'column col-md-12',
29276 html : this.fieldLabel
29280 cls : 'column col-md-12',
29285 if(this.labelAlign == 'left'){
29290 html : this.fieldLabel
29299 if(this.labelWidth > 12){
29300 content[0].style = "width: " + this.labelWidth + 'px';
29303 if(this.labelWidth < 13 && this.labelmd == 0){
29304 this.labelmd = this.labelWidth;
29307 if(this.labellg > 0){
29308 content[0].cls += ' col-lg-' + this.labellg;
29309 content[1].cls += ' col-lg-' + (12 - this.labellg);
29312 if(this.labelmd > 0){
29313 content[0].cls += ' col-md-' + this.labelmd;
29314 content[1].cls += ' col-md-' + (12 - this.labelmd);
29317 if(this.labelsm > 0){
29318 content[0].cls += ' col-sm-' + this.labelsm;
29319 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29322 if(this.labelxs > 0){
29323 content[0].cls += ' col-xs-' + this.labelxs;
29324 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29332 cls : 'row clearfix',
29340 initEvents : function()
29342 this.managerEl = this.el.select('.roo-document-manager', true).first();
29343 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29345 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29346 this.selectorEl.hide();
29349 this.selectorEl.attr('multiple', 'multiple');
29352 this.selectorEl.on('change', this.onFileSelected, this);
29354 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29355 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29357 this.uploader.on('click', this.onUploaderClick, this);
29359 this.renderProgressDialog();
29363 window.addEventListener("resize", function() { _this.refresh(); } );
29365 this.fireEvent('initial', this);
29368 renderProgressDialog : function()
29372 this.progressDialog = new Roo.bootstrap.Modal({
29373 cls : 'roo-document-manager-progress-dialog',
29374 allow_close : false,
29385 btnclick : function() {
29386 _this.uploadCancel();
29392 this.progressDialog.render(Roo.get(document.body));
29394 this.progress = new Roo.bootstrap.Progress({
29395 cls : 'roo-document-manager-progress',
29400 this.progress.render(this.progressDialog.getChildContainer());
29402 this.progressBar = new Roo.bootstrap.ProgressBar({
29403 cls : 'roo-document-manager-progress-bar',
29406 aria_valuemax : 12,
29410 this.progressBar.render(this.progress.getChildContainer());
29413 onUploaderClick : function(e)
29415 e.preventDefault();
29417 if(this.fireEvent('beforeselectfile', this) != false){
29418 this.selectorEl.dom.click();
29423 onFileSelected : function(e)
29425 e.preventDefault();
29427 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29431 Roo.each(this.selectorEl.dom.files, function(file){
29432 if(this.fireEvent('inspect', this, file) != false){
29433 this.files.push(file);
29443 this.selectorEl.dom.value = '';
29445 if(!this.files || !this.files.length){
29449 if(this.boxes > 0 && this.files.length > this.boxes){
29450 this.files = this.files.slice(0, this.boxes);
29453 this.uploader.show();
29455 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29456 this.uploader.hide();
29465 Roo.each(this.files, function(file){
29467 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29468 var f = this.renderPreview(file);
29473 if(file.type.indexOf('image') != -1){
29474 this.delegates.push(
29476 _this.process(file);
29477 }).createDelegate(this)
29485 _this.process(file);
29486 }).createDelegate(this)
29491 this.files = files;
29493 this.delegates = this.delegates.concat(docs);
29495 if(!this.delegates.length){
29500 this.progressBar.aria_valuemax = this.delegates.length;
29507 arrange : function()
29509 if(!this.delegates.length){
29510 this.progressDialog.hide();
29515 var delegate = this.delegates.shift();
29517 this.progressDialog.show();
29519 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29521 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29526 refresh : function()
29528 this.uploader.show();
29530 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29531 this.uploader.hide();
29534 Roo.isTouch ? this.closable(false) : this.closable(true);
29536 this.fireEvent('refresh', this);
29539 onRemove : function(e, el, o)
29541 e.preventDefault();
29543 this.fireEvent('remove', this, o);
29547 remove : function(o)
29551 Roo.each(this.files, function(file){
29552 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29561 this.files = files;
29568 Roo.each(this.files, function(file){
29573 file.target.remove();
29582 onClick : function(e, el, o)
29584 e.preventDefault();
29586 this.fireEvent('click', this, o);
29590 closable : function(closable)
29592 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29594 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29606 xhrOnLoad : function(xhr)
29608 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29612 if (xhr.readyState !== 4) {
29614 this.fireEvent('exception', this, xhr);
29618 var response = Roo.decode(xhr.responseText);
29620 if(!response.success){
29622 this.fireEvent('exception', this, xhr);
29626 var file = this.renderPreview(response.data);
29628 this.files.push(file);
29632 this.fireEvent('afterupload', this, xhr);
29636 xhrOnError : function(xhr)
29638 Roo.log('xhr on error');
29640 var response = Roo.decode(xhr.responseText);
29647 process : function(file)
29649 if(this.fireEvent('process', this, file) !== false){
29650 if(this.editable && file.type.indexOf('image') != -1){
29651 this.fireEvent('edit', this, file);
29655 this.uploadStart(file, false);
29662 uploadStart : function(file, crop)
29664 this.xhr = new XMLHttpRequest();
29666 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29671 file.xhr = this.xhr;
29673 this.managerEl.createChild({
29675 cls : 'roo-document-manager-loading',
29679 tooltip : file.name,
29680 cls : 'roo-document-manager-thumb',
29681 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29687 this.xhr.open(this.method, this.url, true);
29690 "Accept": "application/json",
29691 "Cache-Control": "no-cache",
29692 "X-Requested-With": "XMLHttpRequest"
29695 for (var headerName in headers) {
29696 var headerValue = headers[headerName];
29698 this.xhr.setRequestHeader(headerName, headerValue);
29704 this.xhr.onload = function()
29706 _this.xhrOnLoad(_this.xhr);
29709 this.xhr.onerror = function()
29711 _this.xhrOnError(_this.xhr);
29714 var formData = new FormData();
29716 formData.append('returnHTML', 'NO');
29719 formData.append('crop', crop);
29722 formData.append(this.paramName, file, file.name);
29729 if(this.fireEvent('prepare', this, formData, options) != false){
29731 if(options.manually){
29735 this.xhr.send(formData);
29739 this.uploadCancel();
29742 uploadCancel : function()
29748 this.delegates = [];
29750 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29757 renderPreview : function(file)
29759 if(typeof(file.target) != 'undefined' && file.target){
29763 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29765 var previewEl = this.managerEl.createChild({
29767 cls : 'roo-document-manager-preview',
29771 tooltip : file[this.toolTipName],
29772 cls : 'roo-document-manager-thumb',
29773 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29778 html : '<i class="fa fa-times-circle"></i>'
29783 var close = previewEl.select('button.close', true).first();
29785 close.on('click', this.onRemove, this, file);
29787 file.target = previewEl;
29789 var image = previewEl.select('img', true).first();
29793 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29795 image.on('click', this.onClick, this, file);
29797 this.fireEvent('previewrendered', this, file);
29803 onPreviewLoad : function(file, image)
29805 if(typeof(file.target) == 'undefined' || !file.target){
29809 var width = image.dom.naturalWidth || image.dom.width;
29810 var height = image.dom.naturalHeight || image.dom.height;
29812 if(!this.previewResize) {
29816 if(width > height){
29817 file.target.addClass('wide');
29821 file.target.addClass('tall');
29826 uploadFromSource : function(file, crop)
29828 this.xhr = new XMLHttpRequest();
29830 this.managerEl.createChild({
29832 cls : 'roo-document-manager-loading',
29836 tooltip : file.name,
29837 cls : 'roo-document-manager-thumb',
29838 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29844 this.xhr.open(this.method, this.url, true);
29847 "Accept": "application/json",
29848 "Cache-Control": "no-cache",
29849 "X-Requested-With": "XMLHttpRequest"
29852 for (var headerName in headers) {
29853 var headerValue = headers[headerName];
29855 this.xhr.setRequestHeader(headerName, headerValue);
29861 this.xhr.onload = function()
29863 _this.xhrOnLoad(_this.xhr);
29866 this.xhr.onerror = function()
29868 _this.xhrOnError(_this.xhr);
29871 var formData = new FormData();
29873 formData.append('returnHTML', 'NO');
29875 formData.append('crop', crop);
29877 if(typeof(file.filename) != 'undefined'){
29878 formData.append('filename', file.filename);
29881 if(typeof(file.mimetype) != 'undefined'){
29882 formData.append('mimetype', file.mimetype);
29887 if(this.fireEvent('prepare', this, formData) != false){
29888 this.xhr.send(formData);
29898 * @class Roo.bootstrap.DocumentViewer
29899 * @extends Roo.bootstrap.Component
29900 * Bootstrap DocumentViewer class
29901 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29902 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29905 * Create a new DocumentViewer
29906 * @param {Object} config The config object
29909 Roo.bootstrap.DocumentViewer = function(config){
29910 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29915 * Fire after initEvent
29916 * @param {Roo.bootstrap.DocumentViewer} this
29922 * @param {Roo.bootstrap.DocumentViewer} this
29927 * Fire after download button
29928 * @param {Roo.bootstrap.DocumentViewer} this
29933 * Fire after trash button
29934 * @param {Roo.bootstrap.DocumentViewer} this
29941 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29943 showDownload : true,
29947 getAutoCreate : function()
29951 cls : 'roo-document-viewer',
29955 cls : 'roo-document-viewer-body',
29959 cls : 'roo-document-viewer-thumb',
29963 cls : 'roo-document-viewer-image'
29971 cls : 'roo-document-viewer-footer',
29974 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29978 cls : 'btn-group roo-document-viewer-download',
29982 cls : 'btn btn-default',
29983 html : '<i class="fa fa-download"></i>'
29989 cls : 'btn-group roo-document-viewer-trash',
29993 cls : 'btn btn-default',
29994 html : '<i class="fa fa-trash"></i>'
30007 initEvents : function()
30009 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
30010 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
30012 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
30013 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
30015 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
30016 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
30018 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
30019 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
30021 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
30022 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
30024 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
30025 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
30027 this.bodyEl.on('click', this.onClick, this);
30028 this.downloadBtn.on('click', this.onDownload, this);
30029 this.trashBtn.on('click', this.onTrash, this);
30031 this.downloadBtn.hide();
30032 this.trashBtn.hide();
30034 if(this.showDownload){
30035 this.downloadBtn.show();
30038 if(this.showTrash){
30039 this.trashBtn.show();
30042 if(!this.showDownload && !this.showTrash) {
30043 this.footerEl.hide();
30048 initial : function()
30050 this.fireEvent('initial', this);
30054 onClick : function(e)
30056 e.preventDefault();
30058 this.fireEvent('click', this);
30061 onDownload : function(e)
30063 e.preventDefault();
30065 this.fireEvent('download', this);
30068 onTrash : function(e)
30070 e.preventDefault();
30072 this.fireEvent('trash', this);
30084 * @class Roo.bootstrap.NavProgressBar
30085 * @extends Roo.bootstrap.Component
30086 * Bootstrap NavProgressBar class
30089 * Create a new nav progress bar
30090 * @param {Object} config The config object
30093 Roo.bootstrap.NavProgressBar = function(config){
30094 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30096 this.bullets = this.bullets || [];
30098 // Roo.bootstrap.NavProgressBar.register(this);
30102 * Fires when the active item changes
30103 * @param {Roo.bootstrap.NavProgressBar} this
30104 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30105 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30112 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30117 getAutoCreate : function()
30119 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30123 cls : 'roo-navigation-bar-group',
30127 cls : 'roo-navigation-top-bar'
30131 cls : 'roo-navigation-bullets-bar',
30135 cls : 'roo-navigation-bar'
30142 cls : 'roo-navigation-bottom-bar'
30152 initEvents: function()
30157 onRender : function(ct, position)
30159 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30161 if(this.bullets.length){
30162 Roo.each(this.bullets, function(b){
30171 addItem : function(cfg)
30173 var item = new Roo.bootstrap.NavProgressItem(cfg);
30175 item.parentId = this.id;
30176 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30179 var top = new Roo.bootstrap.Element({
30181 cls : 'roo-navigation-bar-text'
30184 var bottom = new Roo.bootstrap.Element({
30186 cls : 'roo-navigation-bar-text'
30189 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30190 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30192 var topText = new Roo.bootstrap.Element({
30194 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30197 var bottomText = new Roo.bootstrap.Element({
30199 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30202 topText.onRender(top.el, null);
30203 bottomText.onRender(bottom.el, null);
30206 item.bottomEl = bottom;
30209 this.barItems.push(item);
30214 getActive : function()
30216 var active = false;
30218 Roo.each(this.barItems, function(v){
30220 if (!v.isActive()) {
30232 setActiveItem : function(item)
30236 Roo.each(this.barItems, function(v){
30237 if (v.rid == item.rid) {
30241 if (v.isActive()) {
30242 v.setActive(false);
30247 item.setActive(true);
30249 this.fireEvent('changed', this, item, prev);
30252 getBarItem: function(rid)
30256 Roo.each(this.barItems, function(e) {
30257 if (e.rid != rid) {
30268 indexOfItem : function(item)
30272 Roo.each(this.barItems, function(v, i){
30274 if (v.rid != item.rid) {
30285 setActiveNext : function()
30287 var i = this.indexOfItem(this.getActive());
30289 if (i > this.barItems.length) {
30293 this.setActiveItem(this.barItems[i+1]);
30296 setActivePrev : function()
30298 var i = this.indexOfItem(this.getActive());
30304 this.setActiveItem(this.barItems[i-1]);
30307 format : function()
30309 if(!this.barItems.length){
30313 var width = 100 / this.barItems.length;
30315 Roo.each(this.barItems, function(i){
30316 i.el.setStyle('width', width + '%');
30317 i.topEl.el.setStyle('width', width + '%');
30318 i.bottomEl.el.setStyle('width', width + '%');
30327 * Nav Progress Item
30332 * @class Roo.bootstrap.NavProgressItem
30333 * @extends Roo.bootstrap.Component
30334 * Bootstrap NavProgressItem class
30335 * @cfg {String} rid the reference id
30336 * @cfg {Boolean} active (true|false) Is item active default false
30337 * @cfg {Boolean} disabled (true|false) Is item active default false
30338 * @cfg {String} html
30339 * @cfg {String} position (top|bottom) text position default bottom
30340 * @cfg {String} icon show icon instead of number
30343 * Create a new NavProgressItem
30344 * @param {Object} config The config object
30346 Roo.bootstrap.NavProgressItem = function(config){
30347 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30352 * The raw click event for the entire grid.
30353 * @param {Roo.bootstrap.NavProgressItem} this
30354 * @param {Roo.EventObject} e
30361 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30367 position : 'bottom',
30370 getAutoCreate : function()
30372 var iconCls = 'roo-navigation-bar-item-icon';
30374 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30378 cls: 'roo-navigation-bar-item',
30388 cfg.cls += ' active';
30391 cfg.cls += ' disabled';
30397 disable : function()
30399 this.setDisabled(true);
30402 enable : function()
30404 this.setDisabled(false);
30407 initEvents: function()
30409 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30411 this.iconEl.on('click', this.onClick, this);
30414 onClick : function(e)
30416 e.preventDefault();
30422 if(this.fireEvent('click', this, e) === false){
30426 this.parent().setActiveItem(this);
30429 isActive: function ()
30431 return this.active;
30434 setActive : function(state)
30436 if(this.active == state){
30440 this.active = state;
30443 this.el.addClass('active');
30447 this.el.removeClass('active');
30452 setDisabled : function(state)
30454 if(this.disabled == state){
30458 this.disabled = state;
30461 this.el.addClass('disabled');
30465 this.el.removeClass('disabled');
30468 tooltipEl : function()
30470 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30483 * @class Roo.bootstrap.FieldLabel
30484 * @extends Roo.bootstrap.Component
30485 * Bootstrap FieldLabel class
30486 * @cfg {String} html contents of the element
30487 * @cfg {String} tag tag of the element default label
30488 * @cfg {String} cls class of the element
30489 * @cfg {String} target label target
30490 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30491 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30492 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30493 * @cfg {String} iconTooltip default "This field is required"
30494 * @cfg {String} indicatorpos (left|right) default left
30497 * Create a new FieldLabel
30498 * @param {Object} config The config object
30501 Roo.bootstrap.FieldLabel = function(config){
30502 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30507 * Fires after the field has been marked as invalid.
30508 * @param {Roo.form.FieldLabel} this
30509 * @param {String} msg The validation message
30514 * Fires after the field has been validated with no errors.
30515 * @param {Roo.form.FieldLabel} this
30521 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30528 invalidClass : 'has-warning',
30529 validClass : 'has-success',
30530 iconTooltip : 'This field is required',
30531 indicatorpos : 'left',
30533 getAutoCreate : function(){
30536 if (!this.allowBlank) {
30542 cls : 'roo-bootstrap-field-label ' + this.cls,
30547 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30548 tooltip : this.iconTooltip
30557 if(this.indicatorpos == 'right'){
30560 cls : 'roo-bootstrap-field-label ' + this.cls,
30569 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30570 tooltip : this.iconTooltip
30579 initEvents: function()
30581 Roo.bootstrap.Element.superclass.initEvents.call(this);
30583 this.indicator = this.indicatorEl();
30585 if(this.indicator){
30586 this.indicator.removeClass('visible');
30587 this.indicator.addClass('invisible');
30590 Roo.bootstrap.FieldLabel.register(this);
30593 indicatorEl : function()
30595 var indicator = this.el.select('i.roo-required-indicator',true).first();
30606 * Mark this field as valid
30608 markValid : function()
30610 if(this.indicator){
30611 this.indicator.removeClass('visible');
30612 this.indicator.addClass('invisible');
30614 if (Roo.bootstrap.version == 3) {
30615 this.el.removeClass(this.invalidClass);
30616 this.el.addClass(this.validClass);
30618 this.el.removeClass('is-invalid');
30619 this.el.addClass('is-valid');
30623 this.fireEvent('valid', this);
30627 * Mark this field as invalid
30628 * @param {String} msg The validation message
30630 markInvalid : function(msg)
30632 if(this.indicator){
30633 this.indicator.removeClass('invisible');
30634 this.indicator.addClass('visible');
30636 if (Roo.bootstrap.version == 3) {
30637 this.el.removeClass(this.validClass);
30638 this.el.addClass(this.invalidClass);
30640 this.el.removeClass('is-valid');
30641 this.el.addClass('is-invalid');
30645 this.fireEvent('invalid', this, msg);
30651 Roo.apply(Roo.bootstrap.FieldLabel, {
30656 * register a FieldLabel Group
30657 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30659 register : function(label)
30661 if(this.groups.hasOwnProperty(label.target)){
30665 this.groups[label.target] = label;
30669 * fetch a FieldLabel Group based on the target
30670 * @param {string} target
30671 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30673 get: function(target) {
30674 if (typeof(this.groups[target]) == 'undefined') {
30678 return this.groups[target] ;
30687 * page DateSplitField.
30693 * @class Roo.bootstrap.DateSplitField
30694 * @extends Roo.bootstrap.Component
30695 * Bootstrap DateSplitField class
30696 * @cfg {string} fieldLabel - the label associated
30697 * @cfg {Number} labelWidth set the width of label (0-12)
30698 * @cfg {String} labelAlign (top|left)
30699 * @cfg {Boolean} dayAllowBlank (true|false) default false
30700 * @cfg {Boolean} monthAllowBlank (true|false) default false
30701 * @cfg {Boolean} yearAllowBlank (true|false) default false
30702 * @cfg {string} dayPlaceholder
30703 * @cfg {string} monthPlaceholder
30704 * @cfg {string} yearPlaceholder
30705 * @cfg {string} dayFormat default 'd'
30706 * @cfg {string} monthFormat default 'm'
30707 * @cfg {string} yearFormat default 'Y'
30708 * @cfg {Number} labellg set the width of label (1-12)
30709 * @cfg {Number} labelmd set the width of label (1-12)
30710 * @cfg {Number} labelsm set the width of label (1-12)
30711 * @cfg {Number} labelxs set the width of label (1-12)
30715 * Create a new DateSplitField
30716 * @param {Object} config The config object
30719 Roo.bootstrap.DateSplitField = function(config){
30720 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30726 * getting the data of years
30727 * @param {Roo.bootstrap.DateSplitField} this
30728 * @param {Object} years
30733 * getting the data of days
30734 * @param {Roo.bootstrap.DateSplitField} this
30735 * @param {Object} days
30740 * Fires after the field has been marked as invalid.
30741 * @param {Roo.form.Field} this
30742 * @param {String} msg The validation message
30747 * Fires after the field has been validated with no errors.
30748 * @param {Roo.form.Field} this
30754 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30757 labelAlign : 'top',
30759 dayAllowBlank : false,
30760 monthAllowBlank : false,
30761 yearAllowBlank : false,
30762 dayPlaceholder : '',
30763 monthPlaceholder : '',
30764 yearPlaceholder : '',
30768 isFormField : true,
30774 getAutoCreate : function()
30778 cls : 'row roo-date-split-field-group',
30783 cls : 'form-hidden-field roo-date-split-field-group-value',
30789 var labelCls = 'col-md-12';
30790 var contentCls = 'col-md-4';
30792 if(this.fieldLabel){
30796 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30800 html : this.fieldLabel
30805 if(this.labelAlign == 'left'){
30807 if(this.labelWidth > 12){
30808 label.style = "width: " + this.labelWidth + 'px';
30811 if(this.labelWidth < 13 && this.labelmd == 0){
30812 this.labelmd = this.labelWidth;
30815 if(this.labellg > 0){
30816 labelCls = ' col-lg-' + this.labellg;
30817 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30820 if(this.labelmd > 0){
30821 labelCls = ' col-md-' + this.labelmd;
30822 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30825 if(this.labelsm > 0){
30826 labelCls = ' col-sm-' + this.labelsm;
30827 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30830 if(this.labelxs > 0){
30831 labelCls = ' col-xs-' + this.labelxs;
30832 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30836 label.cls += ' ' + labelCls;
30838 cfg.cn.push(label);
30841 Roo.each(['day', 'month', 'year'], function(t){
30844 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30851 inputEl: function ()
30853 return this.el.select('.roo-date-split-field-group-value', true).first();
30856 onRender : function(ct, position)
30860 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30862 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30864 this.dayField = new Roo.bootstrap.ComboBox({
30865 allowBlank : this.dayAllowBlank,
30866 alwaysQuery : true,
30867 displayField : 'value',
30870 forceSelection : true,
30872 placeholder : this.dayPlaceholder,
30873 selectOnFocus : true,
30874 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30875 triggerAction : 'all',
30877 valueField : 'value',
30878 store : new Roo.data.SimpleStore({
30879 data : (function() {
30881 _this.fireEvent('days', _this, days);
30884 fields : [ 'value' ]
30887 select : function (_self, record, index)
30889 _this.setValue(_this.getValue());
30894 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30896 this.monthField = new Roo.bootstrap.MonthField({
30897 after : '<i class=\"fa fa-calendar\"></i>',
30898 allowBlank : this.monthAllowBlank,
30899 placeholder : this.monthPlaceholder,
30902 render : function (_self)
30904 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30905 e.preventDefault();
30909 select : function (_self, oldvalue, newvalue)
30911 _this.setValue(_this.getValue());
30916 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30918 this.yearField = new Roo.bootstrap.ComboBox({
30919 allowBlank : this.yearAllowBlank,
30920 alwaysQuery : true,
30921 displayField : 'value',
30924 forceSelection : true,
30926 placeholder : this.yearPlaceholder,
30927 selectOnFocus : true,
30928 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30929 triggerAction : 'all',
30931 valueField : 'value',
30932 store : new Roo.data.SimpleStore({
30933 data : (function() {
30935 _this.fireEvent('years', _this, years);
30938 fields : [ 'value' ]
30941 select : function (_self, record, index)
30943 _this.setValue(_this.getValue());
30948 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30951 setValue : function(v, format)
30953 this.inputEl.dom.value = v;
30955 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30957 var d = Date.parseDate(v, f);
30964 this.setDay(d.format(this.dayFormat));
30965 this.setMonth(d.format(this.monthFormat));
30966 this.setYear(d.format(this.yearFormat));
30973 setDay : function(v)
30975 this.dayField.setValue(v);
30976 this.inputEl.dom.value = this.getValue();
30981 setMonth : function(v)
30983 this.monthField.setValue(v, true);
30984 this.inputEl.dom.value = this.getValue();
30989 setYear : function(v)
30991 this.yearField.setValue(v);
30992 this.inputEl.dom.value = this.getValue();
30997 getDay : function()
30999 return this.dayField.getValue();
31002 getMonth : function()
31004 return this.monthField.getValue();
31007 getYear : function()
31009 return this.yearField.getValue();
31012 getValue : function()
31014 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
31016 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
31026 this.inputEl.dom.value = '';
31031 validate : function()
31033 var d = this.dayField.validate();
31034 var m = this.monthField.validate();
31035 var y = this.yearField.validate();
31040 (!this.dayAllowBlank && !d) ||
31041 (!this.monthAllowBlank && !m) ||
31042 (!this.yearAllowBlank && !y)
31047 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31056 this.markInvalid();
31061 markValid : function()
31064 var label = this.el.select('label', true).first();
31065 var icon = this.el.select('i.fa-star', true).first();
31071 this.fireEvent('valid', this);
31075 * Mark this field as invalid
31076 * @param {String} msg The validation message
31078 markInvalid : function(msg)
31081 var label = this.el.select('label', true).first();
31082 var icon = this.el.select('i.fa-star', true).first();
31084 if(label && !icon){
31085 this.el.select('.roo-date-split-field-label', true).createChild({
31087 cls : 'text-danger fa fa-lg fa-star',
31088 tooltip : 'This field is required',
31089 style : 'margin-right:5px;'
31093 this.fireEvent('invalid', this, msg);
31096 clearInvalid : function()
31098 var label = this.el.select('label', true).first();
31099 var icon = this.el.select('i.fa-star', true).first();
31105 this.fireEvent('valid', this);
31108 getName: function()
31118 * http://masonry.desandro.com
31120 * The idea is to render all the bricks based on vertical width...
31122 * The original code extends 'outlayer' - we might need to use that....
31128 * @class Roo.bootstrap.LayoutMasonry
31129 * @extends Roo.bootstrap.Component
31130 * Bootstrap Layout Masonry class
31133 * Create a new Element
31134 * @param {Object} config The config object
31137 Roo.bootstrap.LayoutMasonry = function(config){
31139 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31143 Roo.bootstrap.LayoutMasonry.register(this);
31149 * Fire after layout the items
31150 * @param {Roo.bootstrap.LayoutMasonry} this
31151 * @param {Roo.EventObject} e
31158 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31161 * @cfg {Boolean} isLayoutInstant = no animation?
31163 isLayoutInstant : false, // needed?
31166 * @cfg {Number} boxWidth width of the columns
31171 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31176 * @cfg {Number} padWidth padding below box..
31181 * @cfg {Number} gutter gutter width..
31186 * @cfg {Number} maxCols maximum number of columns
31192 * @cfg {Boolean} isAutoInitial defalut true
31194 isAutoInitial : true,
31199 * @cfg {Boolean} isHorizontal defalut false
31201 isHorizontal : false,
31203 currentSize : null,
31209 bricks: null, //CompositeElement
31213 _isLayoutInited : false,
31215 // isAlternative : false, // only use for vertical layout...
31218 * @cfg {Number} alternativePadWidth padding below box..
31220 alternativePadWidth : 50,
31222 selectedBrick : [],
31224 getAutoCreate : function(){
31226 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31230 cls: 'blog-masonary-wrapper ' + this.cls,
31232 cls : 'mas-boxes masonary'
31239 getChildContainer: function( )
31241 if (this.boxesEl) {
31242 return this.boxesEl;
31245 this.boxesEl = this.el.select('.mas-boxes').first();
31247 return this.boxesEl;
31251 initEvents : function()
31255 if(this.isAutoInitial){
31256 Roo.log('hook children rendered');
31257 this.on('childrenrendered', function() {
31258 Roo.log('children rendered');
31264 initial : function()
31266 this.selectedBrick = [];
31268 this.currentSize = this.el.getBox(true);
31270 Roo.EventManager.onWindowResize(this.resize, this);
31272 if(!this.isAutoInitial){
31280 //this.layout.defer(500,this);
31284 resize : function()
31286 var cs = this.el.getBox(true);
31289 this.currentSize.width == cs.width &&
31290 this.currentSize.x == cs.x &&
31291 this.currentSize.height == cs.height &&
31292 this.currentSize.y == cs.y
31294 Roo.log("no change in with or X or Y");
31298 this.currentSize = cs;
31304 layout : function()
31306 this._resetLayout();
31308 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31310 this.layoutItems( isInstant );
31312 this._isLayoutInited = true;
31314 this.fireEvent('layout', this);
31318 _resetLayout : function()
31320 if(this.isHorizontal){
31321 this.horizontalMeasureColumns();
31325 this.verticalMeasureColumns();
31329 verticalMeasureColumns : function()
31331 this.getContainerWidth();
31333 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31334 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31338 var boxWidth = this.boxWidth + this.padWidth;
31340 if(this.containerWidth < this.boxWidth){
31341 boxWidth = this.containerWidth
31344 var containerWidth = this.containerWidth;
31346 var cols = Math.floor(containerWidth / boxWidth);
31348 this.cols = Math.max( cols, 1 );
31350 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31352 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31354 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31356 this.colWidth = boxWidth + avail - this.padWidth;
31358 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31359 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31362 horizontalMeasureColumns : function()
31364 this.getContainerWidth();
31366 var boxWidth = this.boxWidth;
31368 if(this.containerWidth < boxWidth){
31369 boxWidth = this.containerWidth;
31372 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31374 this.el.setHeight(boxWidth);
31378 getContainerWidth : function()
31380 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31383 layoutItems : function( isInstant )
31385 Roo.log(this.bricks);
31387 var items = Roo.apply([], this.bricks);
31389 if(this.isHorizontal){
31390 this._horizontalLayoutItems( items , isInstant );
31394 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31395 // this._verticalAlternativeLayoutItems( items , isInstant );
31399 this._verticalLayoutItems( items , isInstant );
31403 _verticalLayoutItems : function ( items , isInstant)
31405 if ( !items || !items.length ) {
31410 ['xs', 'xs', 'xs', 'tall'],
31411 ['xs', 'xs', 'tall'],
31412 ['xs', 'xs', 'sm'],
31413 ['xs', 'xs', 'xs'],
31419 ['sm', 'xs', 'xs'],
31423 ['tall', 'xs', 'xs', 'xs'],
31424 ['tall', 'xs', 'xs'],
31436 Roo.each(items, function(item, k){
31438 switch (item.size) {
31439 // these layouts take up a full box,
31450 boxes.push([item]);
31473 var filterPattern = function(box, length)
31481 var pattern = box.slice(0, length);
31485 Roo.each(pattern, function(i){
31486 format.push(i.size);
31489 Roo.each(standard, function(s){
31491 if(String(s) != String(format)){
31500 if(!match && length == 1){
31505 filterPattern(box, length - 1);
31509 queue.push(pattern);
31511 box = box.slice(length, box.length);
31513 filterPattern(box, 4);
31519 Roo.each(boxes, function(box, k){
31525 if(box.length == 1){
31530 filterPattern(box, 4);
31534 this._processVerticalLayoutQueue( queue, isInstant );
31538 // _verticalAlternativeLayoutItems : function( items , isInstant )
31540 // if ( !items || !items.length ) {
31544 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31548 _horizontalLayoutItems : function ( items , isInstant)
31550 if ( !items || !items.length || items.length < 3) {
31556 var eItems = items.slice(0, 3);
31558 items = items.slice(3, items.length);
31561 ['xs', 'xs', 'xs', 'wide'],
31562 ['xs', 'xs', 'wide'],
31563 ['xs', 'xs', 'sm'],
31564 ['xs', 'xs', 'xs'],
31570 ['sm', 'xs', 'xs'],
31574 ['wide', 'xs', 'xs', 'xs'],
31575 ['wide', 'xs', 'xs'],
31588 Roo.each(items, function(item, k){
31590 switch (item.size) {
31601 boxes.push([item]);
31625 var filterPattern = function(box, length)
31633 var pattern = box.slice(0, length);
31637 Roo.each(pattern, function(i){
31638 format.push(i.size);
31641 Roo.each(standard, function(s){
31643 if(String(s) != String(format)){
31652 if(!match && length == 1){
31657 filterPattern(box, length - 1);
31661 queue.push(pattern);
31663 box = box.slice(length, box.length);
31665 filterPattern(box, 4);
31671 Roo.each(boxes, function(box, k){
31677 if(box.length == 1){
31682 filterPattern(box, 4);
31689 var pos = this.el.getBox(true);
31693 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31695 var hit_end = false;
31697 Roo.each(queue, function(box){
31701 Roo.each(box, function(b){
31703 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31713 Roo.each(box, function(b){
31715 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31718 mx = Math.max(mx, b.x);
31722 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31726 Roo.each(box, function(b){
31728 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31742 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31745 /** Sets position of item in DOM
31746 * @param {Element} item
31747 * @param {Number} x - horizontal position
31748 * @param {Number} y - vertical position
31749 * @param {Boolean} isInstant - disables transitions
31751 _processVerticalLayoutQueue : function( queue, isInstant )
31753 var pos = this.el.getBox(true);
31758 for (var i = 0; i < this.cols; i++){
31762 Roo.each(queue, function(box, k){
31764 var col = k % this.cols;
31766 Roo.each(box, function(b,kk){
31768 b.el.position('absolute');
31770 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31771 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31773 if(b.size == 'md-left' || b.size == 'md-right'){
31774 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31775 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31778 b.el.setWidth(width);
31779 b.el.setHeight(height);
31781 b.el.select('iframe',true).setSize(width,height);
31785 for (var i = 0; i < this.cols; i++){
31787 if(maxY[i] < maxY[col]){
31792 col = Math.min(col, i);
31796 x = pos.x + col * (this.colWidth + this.padWidth);
31800 var positions = [];
31802 switch (box.length){
31804 positions = this.getVerticalOneBoxColPositions(x, y, box);
31807 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31810 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31813 positions = this.getVerticalFourBoxColPositions(x, y, box);
31819 Roo.each(box, function(b,kk){
31821 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31823 var sz = b.el.getSize();
31825 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31833 for (var i = 0; i < this.cols; i++){
31834 mY = Math.max(mY, maxY[i]);
31837 this.el.setHeight(mY - pos.y);
31841 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31843 // var pos = this.el.getBox(true);
31846 // var maxX = pos.right;
31848 // var maxHeight = 0;
31850 // Roo.each(items, function(item, k){
31854 // item.el.position('absolute');
31856 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31858 // item.el.setWidth(width);
31860 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31862 // item.el.setHeight(height);
31865 // item.el.setXY([x, y], isInstant ? false : true);
31867 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31870 // y = y + height + this.alternativePadWidth;
31872 // maxHeight = maxHeight + height + this.alternativePadWidth;
31876 // this.el.setHeight(maxHeight);
31880 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31882 var pos = this.el.getBox(true);
31887 var maxX = pos.right;
31889 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31891 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31893 Roo.each(queue, function(box, k){
31895 Roo.each(box, function(b, kk){
31897 b.el.position('absolute');
31899 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31900 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31902 if(b.size == 'md-left' || b.size == 'md-right'){
31903 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31904 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31907 b.el.setWidth(width);
31908 b.el.setHeight(height);
31916 var positions = [];
31918 switch (box.length){
31920 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31923 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31926 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31929 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31935 Roo.each(box, function(b,kk){
31937 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31939 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31947 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31949 Roo.each(eItems, function(b,k){
31951 b.size = (k == 0) ? 'sm' : 'xs';
31952 b.x = (k == 0) ? 2 : 1;
31953 b.y = (k == 0) ? 2 : 1;
31955 b.el.position('absolute');
31957 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31959 b.el.setWidth(width);
31961 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31963 b.el.setHeight(height);
31967 var positions = [];
31970 x : maxX - this.unitWidth * 2 - this.gutter,
31975 x : maxX - this.unitWidth,
31976 y : minY + (this.unitWidth + this.gutter) * 2
31980 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31984 Roo.each(eItems, function(b,k){
31986 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31992 getVerticalOneBoxColPositions : function(x, y, box)
31996 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31998 if(box[0].size == 'md-left'){
32002 if(box[0].size == 'md-right'){
32007 x : x + (this.unitWidth + this.gutter) * rand,
32014 getVerticalTwoBoxColPositions : function(x, y, box)
32018 if(box[0].size == 'xs'){
32022 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
32026 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
32040 x : x + (this.unitWidth + this.gutter) * 2,
32041 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32048 getVerticalThreeBoxColPositions : function(x, y, box)
32052 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32060 x : x + (this.unitWidth + this.gutter) * 1,
32065 x : x + (this.unitWidth + this.gutter) * 2,
32073 if(box[0].size == 'xs' && box[1].size == 'xs'){
32082 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32086 x : x + (this.unitWidth + this.gutter) * 1,
32100 x : x + (this.unitWidth + this.gutter) * 2,
32105 x : x + (this.unitWidth + this.gutter) * 2,
32106 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32113 getVerticalFourBoxColPositions : function(x, y, box)
32117 if(box[0].size == 'xs'){
32126 y : y + (this.unitHeight + this.gutter) * 1
32131 y : y + (this.unitHeight + this.gutter) * 2
32135 x : x + (this.unitWidth + this.gutter) * 1,
32149 x : x + (this.unitWidth + this.gutter) * 2,
32154 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32155 y : y + (this.unitHeight + this.gutter) * 1
32159 x : x + (this.unitWidth + this.gutter) * 2,
32160 y : y + (this.unitWidth + this.gutter) * 2
32167 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32171 if(box[0].size == 'md-left'){
32173 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32180 if(box[0].size == 'md-right'){
32182 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32183 y : minY + (this.unitWidth + this.gutter) * 1
32189 var rand = Math.floor(Math.random() * (4 - box[0].y));
32192 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32193 y : minY + (this.unitWidth + this.gutter) * rand
32200 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32204 if(box[0].size == 'xs'){
32207 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32212 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32213 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32221 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32226 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32227 y : minY + (this.unitWidth + this.gutter) * 2
32234 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32238 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32241 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32246 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32247 y : minY + (this.unitWidth + this.gutter) * 1
32251 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32252 y : minY + (this.unitWidth + this.gutter) * 2
32259 if(box[0].size == 'xs' && box[1].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[2].x - this.gutter * (box[2].x - 1),
32273 y : minY + (this.unitWidth + this.gutter) * 1
32281 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32286 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32287 y : minY + (this.unitWidth + this.gutter) * 2
32291 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32292 y : minY + (this.unitWidth + this.gutter) * 2
32299 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32303 if(box[0].size == 'xs'){
32306 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32311 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32316 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),
32321 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32322 y : minY + (this.unitWidth + this.gutter) * 1
32330 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32335 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32336 y : minY + (this.unitWidth + this.gutter) * 2
32340 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32341 y : minY + (this.unitWidth + this.gutter) * 2
32345 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),
32346 y : minY + (this.unitWidth + this.gutter) * 2
32354 * remove a Masonry Brick
32355 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32357 removeBrick : function(brick_id)
32363 for (var i = 0; i<this.bricks.length; i++) {
32364 if (this.bricks[i].id == brick_id) {
32365 this.bricks.splice(i,1);
32366 this.el.dom.removeChild(Roo.get(brick_id).dom);
32373 * adds a Masonry Brick
32374 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32376 addBrick : function(cfg)
32378 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32379 //this.register(cn);
32380 cn.parentId = this.id;
32381 cn.render(this.el);
32386 * register a Masonry Brick
32387 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32390 register : function(brick)
32392 this.bricks.push(brick);
32393 brick.masonryId = this.id;
32397 * clear all the Masonry Brick
32399 clearAll : function()
32402 //this.getChildContainer().dom.innerHTML = "";
32403 this.el.dom.innerHTML = '';
32406 getSelected : function()
32408 if (!this.selectedBrick) {
32412 return this.selectedBrick;
32416 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32420 * register a Masonry Layout
32421 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32424 register : function(layout)
32426 this.groups[layout.id] = layout;
32429 * fetch a Masonry Layout based on the masonry layout ID
32430 * @param {string} the masonry layout to add
32431 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32434 get: function(layout_id) {
32435 if (typeof(this.groups[layout_id]) == 'undefined') {
32438 return this.groups[layout_id] ;
32450 * http://masonry.desandro.com
32452 * The idea is to render all the bricks based on vertical width...
32454 * The original code extends 'outlayer' - we might need to use that....
32460 * @class Roo.bootstrap.LayoutMasonryAuto
32461 * @extends Roo.bootstrap.Component
32462 * Bootstrap Layout Masonry class
32465 * Create a new Element
32466 * @param {Object} config The config object
32469 Roo.bootstrap.LayoutMasonryAuto = function(config){
32470 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32473 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32476 * @cfg {Boolean} isFitWidth - resize the width..
32478 isFitWidth : false, // options..
32480 * @cfg {Boolean} isOriginLeft = left align?
32482 isOriginLeft : true,
32484 * @cfg {Boolean} isOriginTop = top align?
32486 isOriginTop : false,
32488 * @cfg {Boolean} isLayoutInstant = no animation?
32490 isLayoutInstant : false, // needed?
32492 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32494 isResizingContainer : true,
32496 * @cfg {Number} columnWidth width of the columns
32502 * @cfg {Number} maxCols maximum number of columns
32507 * @cfg {Number} padHeight padding below box..
32513 * @cfg {Boolean} isAutoInitial defalut true
32516 isAutoInitial : true,
32522 initialColumnWidth : 0,
32523 currentSize : null,
32525 colYs : null, // array.
32532 bricks: null, //CompositeElement
32533 cols : 0, // array?
32534 // element : null, // wrapped now this.el
32535 _isLayoutInited : null,
32538 getAutoCreate : function(){
32542 cls: 'blog-masonary-wrapper ' + this.cls,
32544 cls : 'mas-boxes masonary'
32551 getChildContainer: function( )
32553 if (this.boxesEl) {
32554 return this.boxesEl;
32557 this.boxesEl = this.el.select('.mas-boxes').first();
32559 return this.boxesEl;
32563 initEvents : function()
32567 if(this.isAutoInitial){
32568 Roo.log('hook children rendered');
32569 this.on('childrenrendered', function() {
32570 Roo.log('children rendered');
32577 initial : function()
32579 this.reloadItems();
32581 this.currentSize = this.el.getBox(true);
32583 /// was window resize... - let's see if this works..
32584 Roo.EventManager.onWindowResize(this.resize, this);
32586 if(!this.isAutoInitial){
32591 this.layout.defer(500,this);
32594 reloadItems: function()
32596 this.bricks = this.el.select('.masonry-brick', true);
32598 this.bricks.each(function(b) {
32599 //Roo.log(b.getSize());
32600 if (!b.attr('originalwidth')) {
32601 b.attr('originalwidth', b.getSize().width);
32606 Roo.log(this.bricks.elements.length);
32609 resize : function()
32612 var cs = this.el.getBox(true);
32614 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32615 Roo.log("no change in with or X");
32618 this.currentSize = cs;
32622 layout : function()
32625 this._resetLayout();
32626 //this._manageStamps();
32628 // don't animate first layout
32629 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32630 this.layoutItems( isInstant );
32632 // flag for initalized
32633 this._isLayoutInited = true;
32636 layoutItems : function( isInstant )
32638 //var items = this._getItemsForLayout( this.items );
32639 // original code supports filtering layout items.. we just ignore it..
32641 this._layoutItems( this.bricks , isInstant );
32643 this._postLayout();
32645 _layoutItems : function ( items , isInstant)
32647 //this.fireEvent( 'layout', this, items );
32650 if ( !items || !items.elements.length ) {
32651 // no items, emit event with empty array
32656 items.each(function(item) {
32657 Roo.log("layout item");
32659 // get x/y object from method
32660 var position = this._getItemLayoutPosition( item );
32662 position.item = item;
32663 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32664 queue.push( position );
32667 this._processLayoutQueue( queue );
32669 /** Sets position of item in DOM
32670 * @param {Element} item
32671 * @param {Number} x - horizontal position
32672 * @param {Number} y - vertical position
32673 * @param {Boolean} isInstant - disables transitions
32675 _processLayoutQueue : function( queue )
32677 for ( var i=0, len = queue.length; i < len; i++ ) {
32678 var obj = queue[i];
32679 obj.item.position('absolute');
32680 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32686 * Any logic you want to do after each layout,
32687 * i.e. size the container
32689 _postLayout : function()
32691 this.resizeContainer();
32694 resizeContainer : function()
32696 if ( !this.isResizingContainer ) {
32699 var size = this._getContainerSize();
32701 this.el.setSize(size.width,size.height);
32702 this.boxesEl.setSize(size.width,size.height);
32708 _resetLayout : function()
32710 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32711 this.colWidth = this.el.getWidth();
32712 //this.gutter = this.el.getWidth();
32714 this.measureColumns();
32720 this.colYs.push( 0 );
32726 measureColumns : function()
32728 this.getContainerWidth();
32729 // if columnWidth is 0, default to outerWidth of first item
32730 if ( !this.columnWidth ) {
32731 var firstItem = this.bricks.first();
32732 Roo.log(firstItem);
32733 this.columnWidth = this.containerWidth;
32734 if (firstItem && firstItem.attr('originalwidth') ) {
32735 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32737 // columnWidth fall back to item of first element
32738 Roo.log("set column width?");
32739 this.initialColumnWidth = this.columnWidth ;
32741 // if first elem has no width, default to size of container
32746 if (this.initialColumnWidth) {
32747 this.columnWidth = this.initialColumnWidth;
32752 // column width is fixed at the top - however if container width get's smaller we should
32755 // this bit calcs how man columns..
32757 var columnWidth = this.columnWidth += this.gutter;
32759 // calculate columns
32760 var containerWidth = this.containerWidth + this.gutter;
32762 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32763 // fix rounding errors, typically with gutters
32764 var excess = columnWidth - containerWidth % columnWidth;
32767 // if overshoot is less than a pixel, round up, otherwise floor it
32768 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32769 cols = Math[ mathMethod ]( cols );
32770 this.cols = Math.max( cols, 1 );
32771 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32773 // padding positioning..
32774 var totalColWidth = this.cols * this.columnWidth;
32775 var padavail = this.containerWidth - totalColWidth;
32776 // so for 2 columns - we need 3 'pads'
32778 var padNeeded = (1+this.cols) * this.padWidth;
32780 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32782 this.columnWidth += padExtra
32783 //this.padWidth = Math.floor(padavail / ( this.cols));
32785 // adjust colum width so that padding is fixed??
32787 // we have 3 columns ... total = width * 3
32788 // we have X left over... that should be used by
32790 //if (this.expandC) {
32798 getContainerWidth : function()
32800 /* // container is parent if fit width
32801 var container = this.isFitWidth ? this.element.parentNode : this.element;
32802 // check that this.size and size are there
32803 // IE8 triggers resize on body size change, so they might not be
32805 var size = getSize( container ); //FIXME
32806 this.containerWidth = size && size.innerWidth; //FIXME
32809 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32813 _getItemLayoutPosition : function( item ) // what is item?
32815 // we resize the item to our columnWidth..
32817 item.setWidth(this.columnWidth);
32818 item.autoBoxAdjust = false;
32820 var sz = item.getSize();
32822 // how many columns does this brick span
32823 var remainder = this.containerWidth % this.columnWidth;
32825 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32826 // round if off by 1 pixel, otherwise use ceil
32827 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32828 colSpan = Math.min( colSpan, this.cols );
32830 // normally this should be '1' as we dont' currently allow multi width columns..
32832 var colGroup = this._getColGroup( colSpan );
32833 // get the minimum Y value from the columns
32834 var minimumY = Math.min.apply( Math, colGroup );
32835 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32837 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32839 // position the brick
32841 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32842 y: this.currentSize.y + minimumY + this.padHeight
32846 // apply setHeight to necessary columns
32847 var setHeight = minimumY + sz.height + this.padHeight;
32848 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32850 var setSpan = this.cols + 1 - colGroup.length;
32851 for ( var i = 0; i < setSpan; i++ ) {
32852 this.colYs[ shortColIndex + i ] = setHeight ;
32859 * @param {Number} colSpan - number of columns the element spans
32860 * @returns {Array} colGroup
32862 _getColGroup : function( colSpan )
32864 if ( colSpan < 2 ) {
32865 // if brick spans only one column, use all the column Ys
32870 // how many different places could this brick fit horizontally
32871 var groupCount = this.cols + 1 - colSpan;
32872 // for each group potential horizontal position
32873 for ( var i = 0; i < groupCount; i++ ) {
32874 // make an array of colY values for that one group
32875 var groupColYs = this.colYs.slice( i, i + colSpan );
32876 // and get the max value of the array
32877 colGroup[i] = Math.max.apply( Math, groupColYs );
32882 _manageStamp : function( stamp )
32884 var stampSize = stamp.getSize();
32885 var offset = stamp.getBox();
32886 // get the columns that this stamp affects
32887 var firstX = this.isOriginLeft ? offset.x : offset.right;
32888 var lastX = firstX + stampSize.width;
32889 var firstCol = Math.floor( firstX / this.columnWidth );
32890 firstCol = Math.max( 0, firstCol );
32892 var lastCol = Math.floor( lastX / this.columnWidth );
32893 // lastCol should not go over if multiple of columnWidth #425
32894 lastCol -= lastX % this.columnWidth ? 0 : 1;
32895 lastCol = Math.min( this.cols - 1, lastCol );
32897 // set colYs to bottom of the stamp
32898 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32901 for ( var i = firstCol; i <= lastCol; i++ ) {
32902 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32907 _getContainerSize : function()
32909 this.maxY = Math.max.apply( Math, this.colYs );
32914 if ( this.isFitWidth ) {
32915 size.width = this._getContainerFitWidth();
32921 _getContainerFitWidth : function()
32923 var unusedCols = 0;
32924 // count unused columns
32927 if ( this.colYs[i] !== 0 ) {
32932 // fit container to columns that have been used
32933 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32936 needsResizeLayout : function()
32938 var previousWidth = this.containerWidth;
32939 this.getContainerWidth();
32940 return previousWidth !== this.containerWidth;
32955 * @class Roo.bootstrap.MasonryBrick
32956 * @extends Roo.bootstrap.Component
32957 * Bootstrap MasonryBrick class
32960 * Create a new MasonryBrick
32961 * @param {Object} config The config object
32964 Roo.bootstrap.MasonryBrick = function(config){
32966 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32968 Roo.bootstrap.MasonryBrick.register(this);
32974 * When a MasonryBrick is clcik
32975 * @param {Roo.bootstrap.MasonryBrick} this
32976 * @param {Roo.EventObject} e
32982 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32985 * @cfg {String} title
32989 * @cfg {String} html
32993 * @cfg {String} bgimage
32997 * @cfg {String} videourl
33001 * @cfg {String} cls
33005 * @cfg {String} href
33009 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
33014 * @cfg {String} placetitle (center|bottom)
33019 * @cfg {Boolean} isFitContainer defalut true
33021 isFitContainer : true,
33024 * @cfg {Boolean} preventDefault defalut false
33026 preventDefault : false,
33029 * @cfg {Boolean} inverse defalut false
33031 maskInverse : false,
33033 getAutoCreate : function()
33035 if(!this.isFitContainer){
33036 return this.getSplitAutoCreate();
33039 var cls = 'masonry-brick masonry-brick-full';
33041 if(this.href.length){
33042 cls += ' masonry-brick-link';
33045 if(this.bgimage.length){
33046 cls += ' masonry-brick-image';
33049 if(this.maskInverse){
33050 cls += ' mask-inverse';
33053 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33054 cls += ' enable-mask';
33058 cls += ' masonry-' + this.size + '-brick';
33061 if(this.placetitle.length){
33063 switch (this.placetitle) {
33065 cls += ' masonry-center-title';
33068 cls += ' masonry-bottom-title';
33075 if(!this.html.length && !this.bgimage.length){
33076 cls += ' masonry-center-title';
33079 if(!this.html.length && this.bgimage.length){
33080 cls += ' masonry-bottom-title';
33085 cls += ' ' + this.cls;
33089 tag: (this.href.length) ? 'a' : 'div',
33094 cls: 'masonry-brick-mask'
33098 cls: 'masonry-brick-paragraph',
33104 if(this.href.length){
33105 cfg.href = this.href;
33108 var cn = cfg.cn[1].cn;
33110 if(this.title.length){
33113 cls: 'masonry-brick-title',
33118 if(this.html.length){
33121 cls: 'masonry-brick-text',
33126 if (!this.title.length && !this.html.length) {
33127 cfg.cn[1].cls += ' hide';
33130 if(this.bgimage.length){
33133 cls: 'masonry-brick-image-view',
33138 if(this.videourl.length){
33139 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33140 // youtube support only?
33143 cls: 'masonry-brick-image-view',
33146 allowfullscreen : true
33154 getSplitAutoCreate : function()
33156 var cls = 'masonry-brick masonry-brick-split';
33158 if(this.href.length){
33159 cls += ' masonry-brick-link';
33162 if(this.bgimage.length){
33163 cls += ' masonry-brick-image';
33167 cls += ' masonry-' + this.size + '-brick';
33170 switch (this.placetitle) {
33172 cls += ' masonry-center-title';
33175 cls += ' masonry-bottom-title';
33178 if(!this.bgimage.length){
33179 cls += ' masonry-center-title';
33182 if(this.bgimage.length){
33183 cls += ' masonry-bottom-title';
33189 cls += ' ' + this.cls;
33193 tag: (this.href.length) ? 'a' : 'div',
33198 cls: 'masonry-brick-split-head',
33202 cls: 'masonry-brick-paragraph',
33209 cls: 'masonry-brick-split-body',
33215 if(this.href.length){
33216 cfg.href = this.href;
33219 if(this.title.length){
33220 cfg.cn[0].cn[0].cn.push({
33222 cls: 'masonry-brick-title',
33227 if(this.html.length){
33228 cfg.cn[1].cn.push({
33230 cls: 'masonry-brick-text',
33235 if(this.bgimage.length){
33236 cfg.cn[0].cn.push({
33238 cls: 'masonry-brick-image-view',
33243 if(this.videourl.length){
33244 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33245 // youtube support only?
33246 cfg.cn[0].cn.cn.push({
33248 cls: 'masonry-brick-image-view',
33251 allowfullscreen : true
33258 initEvents: function()
33260 switch (this.size) {
33293 this.el.on('touchstart', this.onTouchStart, this);
33294 this.el.on('touchmove', this.onTouchMove, this);
33295 this.el.on('touchend', this.onTouchEnd, this);
33296 this.el.on('contextmenu', this.onContextMenu, this);
33298 this.el.on('mouseenter' ,this.enter, this);
33299 this.el.on('mouseleave', this.leave, this);
33300 this.el.on('click', this.onClick, this);
33303 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33304 this.parent().bricks.push(this);
33309 onClick: function(e, el)
33311 var time = this.endTimer - this.startTimer;
33312 // Roo.log(e.preventDefault());
33315 e.preventDefault();
33320 if(!this.preventDefault){
33324 e.preventDefault();
33326 if (this.activeClass != '') {
33327 this.selectBrick();
33330 this.fireEvent('click', this, e);
33333 enter: function(e, el)
33335 e.preventDefault();
33337 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33341 if(this.bgimage.length && this.html.length){
33342 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33346 leave: function(e, el)
33348 e.preventDefault();
33350 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33354 if(this.bgimage.length && this.html.length){
33355 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33359 onTouchStart: function(e, el)
33361 // e.preventDefault();
33363 this.touchmoved = false;
33365 if(!this.isFitContainer){
33369 if(!this.bgimage.length || !this.html.length){
33373 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33375 this.timer = new Date().getTime();
33379 onTouchMove: function(e, el)
33381 this.touchmoved = true;
33384 onContextMenu : function(e,el)
33386 e.preventDefault();
33387 e.stopPropagation();
33391 onTouchEnd: function(e, el)
33393 // e.preventDefault();
33395 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33402 if(!this.bgimage.length || !this.html.length){
33404 if(this.href.length){
33405 window.location.href = this.href;
33411 if(!this.isFitContainer){
33415 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33417 window.location.href = this.href;
33420 //selection on single brick only
33421 selectBrick : function() {
33423 if (!this.parentId) {
33427 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33428 var index = m.selectedBrick.indexOf(this.id);
33431 m.selectedBrick.splice(index,1);
33432 this.el.removeClass(this.activeClass);
33436 for(var i = 0; i < m.selectedBrick.length; i++) {
33437 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33438 b.el.removeClass(b.activeClass);
33441 m.selectedBrick = [];
33443 m.selectedBrick.push(this.id);
33444 this.el.addClass(this.activeClass);
33448 isSelected : function(){
33449 return this.el.hasClass(this.activeClass);
33454 Roo.apply(Roo.bootstrap.MasonryBrick, {
33457 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33459 * register a Masonry Brick
33460 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33463 register : function(brick)
33465 //this.groups[brick.id] = brick;
33466 this.groups.add(brick.id, brick);
33469 * fetch a masonry brick based on the masonry brick ID
33470 * @param {string} the masonry brick to add
33471 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33474 get: function(brick_id)
33476 // if (typeof(this.groups[brick_id]) == 'undefined') {
33479 // return this.groups[brick_id] ;
33481 if(this.groups.key(brick_id)) {
33482 return this.groups.key(brick_id);
33500 * @class Roo.bootstrap.Brick
33501 * @extends Roo.bootstrap.Component
33502 * Bootstrap Brick class
33505 * Create a new Brick
33506 * @param {Object} config The config object
33509 Roo.bootstrap.Brick = function(config){
33510 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33516 * When a Brick is click
33517 * @param {Roo.bootstrap.Brick} this
33518 * @param {Roo.EventObject} e
33524 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33527 * @cfg {String} title
33531 * @cfg {String} html
33535 * @cfg {String} bgimage
33539 * @cfg {String} cls
33543 * @cfg {String} href
33547 * @cfg {String} video
33551 * @cfg {Boolean} square
33555 getAutoCreate : function()
33557 var cls = 'roo-brick';
33559 if(this.href.length){
33560 cls += ' roo-brick-link';
33563 if(this.bgimage.length){
33564 cls += ' roo-brick-image';
33567 if(!this.html.length && !this.bgimage.length){
33568 cls += ' roo-brick-center-title';
33571 if(!this.html.length && this.bgimage.length){
33572 cls += ' roo-brick-bottom-title';
33576 cls += ' ' + this.cls;
33580 tag: (this.href.length) ? 'a' : 'div',
33585 cls: 'roo-brick-paragraph',
33591 if(this.href.length){
33592 cfg.href = this.href;
33595 var cn = cfg.cn[0].cn;
33597 if(this.title.length){
33600 cls: 'roo-brick-title',
33605 if(this.html.length){
33608 cls: 'roo-brick-text',
33615 if(this.bgimage.length){
33618 cls: 'roo-brick-image-view',
33626 initEvents: function()
33628 if(this.title.length || this.html.length){
33629 this.el.on('mouseenter' ,this.enter, this);
33630 this.el.on('mouseleave', this.leave, this);
33633 Roo.EventManager.onWindowResize(this.resize, this);
33635 if(this.bgimage.length){
33636 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33637 this.imageEl.on('load', this.onImageLoad, this);
33644 onImageLoad : function()
33649 resize : function()
33651 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33653 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33655 if(this.bgimage.length){
33656 var image = this.el.select('.roo-brick-image-view', true).first();
33658 image.setWidth(paragraph.getWidth());
33661 image.setHeight(paragraph.getWidth());
33664 this.el.setHeight(image.getHeight());
33665 paragraph.setHeight(image.getHeight());
33671 enter: function(e, el)
33673 e.preventDefault();
33675 if(this.bgimage.length){
33676 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33677 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33681 leave: function(e, el)
33683 e.preventDefault();
33685 if(this.bgimage.length){
33686 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33687 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33702 * @class Roo.bootstrap.NumberField
33703 * @extends Roo.bootstrap.Input
33704 * Bootstrap NumberField class
33710 * Create a new NumberField
33711 * @param {Object} config The config object
33714 Roo.bootstrap.NumberField = function(config){
33715 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33718 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33721 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33723 allowDecimals : true,
33725 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33727 decimalSeparator : ".",
33729 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33731 decimalPrecision : 2,
33733 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33735 allowNegative : true,
33738 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33742 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33744 minValue : Number.NEGATIVE_INFINITY,
33746 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33748 maxValue : Number.MAX_VALUE,
33750 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33752 minText : "The minimum value for this field is {0}",
33754 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33756 maxText : "The maximum value for this field is {0}",
33758 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33759 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33761 nanText : "{0} is not a valid number",
33763 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33765 thousandsDelimiter : false,
33767 * @cfg {String} valueAlign alignment of value
33769 valueAlign : "left",
33771 getAutoCreate : function()
33773 var hiddenInput = {
33777 cls: 'hidden-number-input'
33781 hiddenInput.name = this.name;
33786 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33788 this.name = hiddenInput.name;
33790 if(cfg.cn.length > 0) {
33791 cfg.cn.push(hiddenInput);
33798 initEvents : function()
33800 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33802 var allowed = "0123456789";
33804 if(this.allowDecimals){
33805 allowed += this.decimalSeparator;
33808 if(this.allowNegative){
33812 if(this.thousandsDelimiter) {
33816 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33818 var keyPress = function(e){
33820 var k = e.getKey();
33822 var c = e.getCharCode();
33825 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33826 allowed.indexOf(String.fromCharCode(c)) === -1
33832 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33836 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33841 this.el.on("keypress", keyPress, this);
33844 validateValue : function(value)
33847 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33851 var num = this.parseValue(value);
33854 this.markInvalid(String.format(this.nanText, value));
33858 if(num < this.minValue){
33859 this.markInvalid(String.format(this.minText, this.minValue));
33863 if(num > this.maxValue){
33864 this.markInvalid(String.format(this.maxText, this.maxValue));
33871 getValue : function()
33873 var v = this.hiddenEl().getValue();
33875 return this.fixPrecision(this.parseValue(v));
33878 parseValue : function(value)
33880 if(this.thousandsDelimiter) {
33882 r = new RegExp(",", "g");
33883 value = value.replace(r, "");
33886 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33887 return isNaN(value) ? '' : value;
33890 fixPrecision : function(value)
33892 if(this.thousandsDelimiter) {
33894 r = new RegExp(",", "g");
33895 value = value.replace(r, "");
33898 var nan = isNaN(value);
33900 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33901 return nan ? '' : value;
33903 return parseFloat(value).toFixed(this.decimalPrecision);
33906 setValue : function(v)
33908 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33914 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33916 this.inputEl().dom.value = (v == '') ? '' :
33917 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33919 if(!this.allowZero && v === '0') {
33920 this.hiddenEl().dom.value = '';
33921 this.inputEl().dom.value = '';
33928 decimalPrecisionFcn : function(v)
33930 return Math.floor(v);
33933 beforeBlur : function()
33935 var v = this.parseValue(this.getRawValue());
33937 if(v || v === 0 || v === ''){
33942 hiddenEl : function()
33944 return this.el.select('input.hidden-number-input',true).first();
33956 * @class Roo.bootstrap.DocumentSlider
33957 * @extends Roo.bootstrap.Component
33958 * Bootstrap DocumentSlider class
33961 * Create a new DocumentViewer
33962 * @param {Object} config The config object
33965 Roo.bootstrap.DocumentSlider = function(config){
33966 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33973 * Fire after initEvent
33974 * @param {Roo.bootstrap.DocumentSlider} this
33979 * Fire after update
33980 * @param {Roo.bootstrap.DocumentSlider} this
33986 * @param {Roo.bootstrap.DocumentSlider} this
33992 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33998 getAutoCreate : function()
34002 cls : 'roo-document-slider',
34006 cls : 'roo-document-slider-header',
34010 cls : 'roo-document-slider-header-title'
34016 cls : 'roo-document-slider-body',
34020 cls : 'roo-document-slider-prev',
34024 cls : 'fa fa-chevron-left'
34030 cls : 'roo-document-slider-thumb',
34034 cls : 'roo-document-slider-image'
34040 cls : 'roo-document-slider-next',
34044 cls : 'fa fa-chevron-right'
34056 initEvents : function()
34058 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34059 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34061 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34062 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34064 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34065 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34067 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34068 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34070 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34071 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34073 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34074 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34076 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34077 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34079 this.thumbEl.on('click', this.onClick, this);
34081 this.prevIndicator.on('click', this.prev, this);
34083 this.nextIndicator.on('click', this.next, this);
34087 initial : function()
34089 if(this.files.length){
34090 this.indicator = 1;
34094 this.fireEvent('initial', this);
34097 update : function()
34099 this.imageEl.attr('src', this.files[this.indicator - 1]);
34101 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34103 this.prevIndicator.show();
34105 if(this.indicator == 1){
34106 this.prevIndicator.hide();
34109 this.nextIndicator.show();
34111 if(this.indicator == this.files.length){
34112 this.nextIndicator.hide();
34115 this.thumbEl.scrollTo('top');
34117 this.fireEvent('update', this);
34120 onClick : function(e)
34122 e.preventDefault();
34124 this.fireEvent('click', this);
34129 e.preventDefault();
34131 this.indicator = Math.max(1, this.indicator - 1);
34138 e.preventDefault();
34140 this.indicator = Math.min(this.files.length, this.indicator + 1);
34154 * @class Roo.bootstrap.RadioSet
34155 * @extends Roo.bootstrap.Input
34156 * Bootstrap RadioSet class
34157 * @cfg {String} indicatorpos (left|right) default left
34158 * @cfg {Boolean} inline (true|false) inline the element (default true)
34159 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34161 * Create a new RadioSet
34162 * @param {Object} config The config object
34165 Roo.bootstrap.RadioSet = function(config){
34167 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34171 Roo.bootstrap.RadioSet.register(this);
34176 * Fires when the element is checked or unchecked.
34177 * @param {Roo.bootstrap.RadioSet} this This radio
34178 * @param {Roo.bootstrap.Radio} item The checked item
34183 * Fires when the element is click.
34184 * @param {Roo.bootstrap.RadioSet} this This radio set
34185 * @param {Roo.bootstrap.Radio} item The checked item
34186 * @param {Roo.EventObject} e The event object
34193 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34201 indicatorpos : 'left',
34203 getAutoCreate : function()
34207 cls : 'roo-radio-set-label',
34211 html : this.fieldLabel
34215 if (Roo.bootstrap.version == 3) {
34218 if(this.indicatorpos == 'left'){
34221 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34222 tooltip : 'This field is required'
34227 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34228 tooltip : 'This field is required'
34234 cls : 'roo-radio-set-items'
34237 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34239 if (align === 'left' && this.fieldLabel.length) {
34242 cls : "roo-radio-set-right",
34248 if(this.labelWidth > 12){
34249 label.style = "width: " + this.labelWidth + 'px';
34252 if(this.labelWidth < 13 && this.labelmd == 0){
34253 this.labelmd = this.labelWidth;
34256 if(this.labellg > 0){
34257 label.cls += ' col-lg-' + this.labellg;
34258 items.cls += ' col-lg-' + (12 - this.labellg);
34261 if(this.labelmd > 0){
34262 label.cls += ' col-md-' + this.labelmd;
34263 items.cls += ' col-md-' + (12 - this.labelmd);
34266 if(this.labelsm > 0){
34267 label.cls += ' col-sm-' + this.labelsm;
34268 items.cls += ' col-sm-' + (12 - this.labelsm);
34271 if(this.labelxs > 0){
34272 label.cls += ' col-xs-' + this.labelxs;
34273 items.cls += ' col-xs-' + (12 - this.labelxs);
34279 cls : 'roo-radio-set',
34283 cls : 'roo-radio-set-input',
34286 value : this.value ? this.value : ''
34293 if(this.weight.length){
34294 cfg.cls += ' roo-radio-' + this.weight;
34298 cfg.cls += ' roo-radio-set-inline';
34302 ['xs','sm','md','lg'].map(function(size){
34303 if (settings[size]) {
34304 cfg.cls += ' col-' + size + '-' + settings[size];
34312 initEvents : function()
34314 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34315 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34317 if(!this.fieldLabel.length){
34318 this.labelEl.hide();
34321 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34322 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34324 this.indicator = this.indicatorEl();
34326 if(this.indicator){
34327 this.indicator.addClass('invisible');
34330 this.originalValue = this.getValue();
34334 inputEl: function ()
34336 return this.el.select('.roo-radio-set-input', true).first();
34339 getChildContainer : function()
34341 return this.itemsEl;
34344 register : function(item)
34346 this.radioes.push(item);
34350 validate : function()
34352 if(this.getVisibilityEl().hasClass('hidden')){
34358 Roo.each(this.radioes, function(i){
34367 if(this.allowBlank) {
34371 if(this.disabled || valid){
34376 this.markInvalid();
34381 markValid : function()
34383 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34384 this.indicatorEl().removeClass('visible');
34385 this.indicatorEl().addClass('invisible');
34389 if (Roo.bootstrap.version == 3) {
34390 this.el.removeClass([this.invalidClass, this.validClass]);
34391 this.el.addClass(this.validClass);
34393 this.el.removeClass(['is-invalid','is-valid']);
34394 this.el.addClass(['is-valid']);
34396 this.fireEvent('valid', this);
34399 markInvalid : function(msg)
34401 if(this.allowBlank || this.disabled){
34405 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34406 this.indicatorEl().removeClass('invisible');
34407 this.indicatorEl().addClass('visible');
34409 if (Roo.bootstrap.version == 3) {
34410 this.el.removeClass([this.invalidClass, this.validClass]);
34411 this.el.addClass(this.invalidClass);
34413 this.el.removeClass(['is-invalid','is-valid']);
34414 this.el.addClass(['is-invalid']);
34417 this.fireEvent('invalid', this, msg);
34421 setValue : function(v, suppressEvent)
34423 if(this.value === v){
34430 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34433 Roo.each(this.radioes, function(i){
34435 i.el.removeClass('checked');
34438 Roo.each(this.radioes, function(i){
34440 if(i.value === v || i.value.toString() === v.toString()){
34442 i.el.addClass('checked');
34444 if(suppressEvent !== true){
34445 this.fireEvent('check', this, i);
34456 clearInvalid : function(){
34458 if(!this.el || this.preventMark){
34462 this.el.removeClass([this.invalidClass]);
34464 this.fireEvent('valid', this);
34469 Roo.apply(Roo.bootstrap.RadioSet, {
34473 register : function(set)
34475 this.groups[set.name] = set;
34478 get: function(name)
34480 if (typeof(this.groups[name]) == 'undefined') {
34484 return this.groups[name] ;
34490 * Ext JS Library 1.1.1
34491 * Copyright(c) 2006-2007, Ext JS, LLC.
34493 * Originally Released Under LGPL - original licence link has changed is not relivant.
34496 * <script type="text/javascript">
34501 * @class Roo.bootstrap.SplitBar
34502 * @extends Roo.util.Observable
34503 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34507 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34508 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34509 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34510 split.minSize = 100;
34511 split.maxSize = 600;
34512 split.animate = true;
34513 split.on('moved', splitterMoved);
34516 * Create a new SplitBar
34517 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34518 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34519 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34520 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34521 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34522 position of the SplitBar).
34524 Roo.bootstrap.SplitBar = function(cfg){
34529 // dragElement : elm
34530 // resizingElement: el,
34532 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34533 // placement : Roo.bootstrap.SplitBar.LEFT ,
34534 // existingProxy ???
34537 this.el = Roo.get(cfg.dragElement, true);
34538 this.el.dom.unselectable = "on";
34540 this.resizingEl = Roo.get(cfg.resizingElement, true);
34544 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34545 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34548 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34551 * The minimum size of the resizing element. (Defaults to 0)
34557 * The maximum size of the resizing element. (Defaults to 2000)
34560 this.maxSize = 2000;
34563 * Whether to animate the transition to the new size
34566 this.animate = false;
34569 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34572 this.useShim = false;
34577 if(!cfg.existingProxy){
34579 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34581 this.proxy = Roo.get(cfg.existingProxy).dom;
34584 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34587 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34590 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34593 this.dragSpecs = {};
34596 * @private The adapter to use to positon and resize elements
34598 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34599 this.adapter.init(this);
34601 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34603 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34604 this.el.addClass("roo-splitbar-h");
34607 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34608 this.el.addClass("roo-splitbar-v");
34614 * Fires when the splitter is moved (alias for {@link #event-moved})
34615 * @param {Roo.bootstrap.SplitBar} this
34616 * @param {Number} newSize the new width or height
34621 * Fires when the splitter is moved
34622 * @param {Roo.bootstrap.SplitBar} this
34623 * @param {Number} newSize the new width or height
34627 * @event beforeresize
34628 * Fires before the splitter is dragged
34629 * @param {Roo.bootstrap.SplitBar} this
34631 "beforeresize" : true,
34633 "beforeapply" : true
34636 Roo.util.Observable.call(this);
34639 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34640 onStartProxyDrag : function(x, y){
34641 this.fireEvent("beforeresize", this);
34643 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34645 o.enableDisplayMode("block");
34646 // all splitbars share the same overlay
34647 Roo.bootstrap.SplitBar.prototype.overlay = o;
34649 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34650 this.overlay.show();
34651 Roo.get(this.proxy).setDisplayed("block");
34652 var size = this.adapter.getElementSize(this);
34653 this.activeMinSize = this.getMinimumSize();;
34654 this.activeMaxSize = this.getMaximumSize();;
34655 var c1 = size - this.activeMinSize;
34656 var c2 = Math.max(this.activeMaxSize - size, 0);
34657 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34658 this.dd.resetConstraints();
34659 this.dd.setXConstraint(
34660 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34661 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34663 this.dd.setYConstraint(0, 0);
34665 this.dd.resetConstraints();
34666 this.dd.setXConstraint(0, 0);
34667 this.dd.setYConstraint(
34668 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34669 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34672 this.dragSpecs.startSize = size;
34673 this.dragSpecs.startPoint = [x, y];
34674 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34678 * @private Called after the drag operation by the DDProxy
34680 onEndProxyDrag : function(e){
34681 Roo.get(this.proxy).setDisplayed(false);
34682 var endPoint = Roo.lib.Event.getXY(e);
34684 this.overlay.hide();
34687 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34688 newSize = this.dragSpecs.startSize +
34689 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34690 endPoint[0] - this.dragSpecs.startPoint[0] :
34691 this.dragSpecs.startPoint[0] - endPoint[0]
34694 newSize = this.dragSpecs.startSize +
34695 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34696 endPoint[1] - this.dragSpecs.startPoint[1] :
34697 this.dragSpecs.startPoint[1] - endPoint[1]
34700 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34701 if(newSize != this.dragSpecs.startSize){
34702 if(this.fireEvent('beforeapply', this, newSize) !== false){
34703 this.adapter.setElementSize(this, newSize);
34704 this.fireEvent("moved", this, newSize);
34705 this.fireEvent("resize", this, newSize);
34711 * Get the adapter this SplitBar uses
34712 * @return The adapter object
34714 getAdapter : function(){
34715 return this.adapter;
34719 * Set the adapter this SplitBar uses
34720 * @param {Object} adapter A SplitBar adapter object
34722 setAdapter : function(adapter){
34723 this.adapter = adapter;
34724 this.adapter.init(this);
34728 * Gets the minimum size for the resizing element
34729 * @return {Number} The minimum size
34731 getMinimumSize : function(){
34732 return this.minSize;
34736 * Sets the minimum size for the resizing element
34737 * @param {Number} minSize The minimum size
34739 setMinimumSize : function(minSize){
34740 this.minSize = minSize;
34744 * Gets the maximum size for the resizing element
34745 * @return {Number} The maximum size
34747 getMaximumSize : function(){
34748 return this.maxSize;
34752 * Sets the maximum size for the resizing element
34753 * @param {Number} maxSize The maximum size
34755 setMaximumSize : function(maxSize){
34756 this.maxSize = maxSize;
34760 * Sets the initialize size for the resizing element
34761 * @param {Number} size The initial size
34763 setCurrentSize : function(size){
34764 var oldAnimate = this.animate;
34765 this.animate = false;
34766 this.adapter.setElementSize(this, size);
34767 this.animate = oldAnimate;
34771 * Destroy this splitbar.
34772 * @param {Boolean} removeEl True to remove the element
34774 destroy : function(removeEl){
34776 this.shim.remove();
34779 this.proxy.parentNode.removeChild(this.proxy);
34787 * @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.
34789 Roo.bootstrap.SplitBar.createProxy = function(dir){
34790 var proxy = new Roo.Element(document.createElement("div"));
34791 proxy.unselectable();
34792 var cls = 'roo-splitbar-proxy';
34793 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34794 document.body.appendChild(proxy.dom);
34799 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34800 * Default Adapter. It assumes the splitter and resizing element are not positioned
34801 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34803 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34806 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34807 // do nothing for now
34808 init : function(s){
34812 * Called before drag operations to get the current size of the resizing element.
34813 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34815 getElementSize : function(s){
34816 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34817 return s.resizingEl.getWidth();
34819 return s.resizingEl.getHeight();
34824 * Called after drag operations to set the size of the resizing element.
34825 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34826 * @param {Number} newSize The new size to set
34827 * @param {Function} onComplete A function to be invoked when resizing is complete
34829 setElementSize : function(s, newSize, onComplete){
34830 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34832 s.resizingEl.setWidth(newSize);
34834 onComplete(s, newSize);
34837 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34842 s.resizingEl.setHeight(newSize);
34844 onComplete(s, newSize);
34847 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34854 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34855 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34856 * Adapter that moves the splitter element to align with the resized sizing element.
34857 * Used with an absolute positioned SplitBar.
34858 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34859 * document.body, make sure you assign an id to the body element.
34861 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34862 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34863 this.container = Roo.get(container);
34866 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34867 init : function(s){
34868 this.basic.init(s);
34871 getElementSize : function(s){
34872 return this.basic.getElementSize(s);
34875 setElementSize : function(s, newSize, onComplete){
34876 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34879 moveSplitter : function(s){
34880 var yes = Roo.bootstrap.SplitBar;
34881 switch(s.placement){
34883 s.el.setX(s.resizingEl.getRight());
34886 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34889 s.el.setY(s.resizingEl.getBottom());
34892 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34899 * Orientation constant - Create a vertical SplitBar
34903 Roo.bootstrap.SplitBar.VERTICAL = 1;
34906 * Orientation constant - Create a horizontal SplitBar
34910 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34913 * Placement constant - The resizing element is to the left of the splitter element
34917 Roo.bootstrap.SplitBar.LEFT = 1;
34920 * Placement constant - The resizing element is to the right of the splitter element
34924 Roo.bootstrap.SplitBar.RIGHT = 2;
34927 * Placement constant - The resizing element is positioned above the splitter element
34931 Roo.bootstrap.SplitBar.TOP = 3;
34934 * Placement constant - The resizing element is positioned under splitter element
34938 Roo.bootstrap.SplitBar.BOTTOM = 4;
34939 Roo.namespace("Roo.bootstrap.layout");/*
34941 * Ext JS Library 1.1.1
34942 * Copyright(c) 2006-2007, Ext JS, LLC.
34944 * Originally Released Under LGPL - original licence link has changed is not relivant.
34947 * <script type="text/javascript">
34951 * @class Roo.bootstrap.layout.Manager
34952 * @extends Roo.bootstrap.Component
34953 * Base class for layout managers.
34955 Roo.bootstrap.layout.Manager = function(config)
34957 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34963 /** false to disable window resize monitoring @type Boolean */
34964 this.monitorWindowResize = true;
34969 * Fires when a layout is performed.
34970 * @param {Roo.LayoutManager} this
34974 * @event regionresized
34975 * Fires when the user resizes a region.
34976 * @param {Roo.LayoutRegion} region The resized region
34977 * @param {Number} newSize The new size (width for east/west, height for north/south)
34979 "regionresized" : true,
34981 * @event regioncollapsed
34982 * Fires when a region is collapsed.
34983 * @param {Roo.LayoutRegion} region The collapsed region
34985 "regioncollapsed" : true,
34987 * @event regionexpanded
34988 * Fires when a region is expanded.
34989 * @param {Roo.LayoutRegion} region The expanded region
34991 "regionexpanded" : true
34993 this.updating = false;
34996 this.el = Roo.get(config.el);
35002 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
35007 monitorWindowResize : true,
35013 onRender : function(ct, position)
35016 this.el = Roo.get(ct);
35019 //this.fireEvent('render',this);
35023 initEvents: function()
35027 // ie scrollbar fix
35028 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
35029 document.body.scroll = "no";
35030 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
35031 this.el.position('relative');
35033 this.id = this.el.id;
35034 this.el.addClass("roo-layout-container");
35035 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
35036 if(this.el.dom != document.body ) {
35037 this.el.on('resize', this.layout,this);
35038 this.el.on('show', this.layout,this);
35044 * Returns true if this layout is currently being updated
35045 * @return {Boolean}
35047 isUpdating : function(){
35048 return this.updating;
35052 * Suspend the LayoutManager from doing auto-layouts while
35053 * making multiple add or remove calls
35055 beginUpdate : function(){
35056 this.updating = true;
35060 * Restore auto-layouts and optionally disable the manager from performing a layout
35061 * @param {Boolean} noLayout true to disable a layout update
35063 endUpdate : function(noLayout){
35064 this.updating = false;
35070 layout: function(){
35074 onRegionResized : function(region, newSize){
35075 this.fireEvent("regionresized", region, newSize);
35079 onRegionCollapsed : function(region){
35080 this.fireEvent("regioncollapsed", region);
35083 onRegionExpanded : function(region){
35084 this.fireEvent("regionexpanded", region);
35088 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35089 * performs box-model adjustments.
35090 * @return {Object} The size as an object {width: (the width), height: (the height)}
35092 getViewSize : function()
35095 if(this.el.dom != document.body){
35096 size = this.el.getSize();
35098 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35100 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35101 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35106 * Returns the Element this layout is bound to.
35107 * @return {Roo.Element}
35109 getEl : function(){
35114 * Returns the specified region.
35115 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35116 * @return {Roo.LayoutRegion}
35118 getRegion : function(target){
35119 return this.regions[target.toLowerCase()];
35122 onWindowResize : function(){
35123 if(this.monitorWindowResize){
35130 * Ext JS Library 1.1.1
35131 * Copyright(c) 2006-2007, Ext JS, LLC.
35133 * Originally Released Under LGPL - original licence link has changed is not relivant.
35136 * <script type="text/javascript">
35139 * @class Roo.bootstrap.layout.Border
35140 * @extends Roo.bootstrap.layout.Manager
35141 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35142 * please see: examples/bootstrap/nested.html<br><br>
35144 <b>The container the layout is rendered into can be either the body element or any other element.
35145 If it is not the body element, the container needs to either be an absolute positioned element,
35146 or you will need to add "position:relative" to the css of the container. You will also need to specify
35147 the container size if it is not the body element.</b>
35150 * Create a new Border
35151 * @param {Object} config Configuration options
35153 Roo.bootstrap.layout.Border = function(config){
35154 config = config || {};
35155 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35159 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35160 if(config[region]){
35161 config[region].region = region;
35162 this.addRegion(config[region]);
35168 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35170 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35172 parent : false, // this might point to a 'nest' or a ???
35175 * Creates and adds a new region if it doesn't already exist.
35176 * @param {String} target The target region key (north, south, east, west or center).
35177 * @param {Object} config The regions config object
35178 * @return {BorderLayoutRegion} The new region
35180 addRegion : function(config)
35182 if(!this.regions[config.region]){
35183 var r = this.factory(config);
35184 this.bindRegion(r);
35186 return this.regions[config.region];
35190 bindRegion : function(r){
35191 this.regions[r.config.region] = r;
35193 r.on("visibilitychange", this.layout, this);
35194 r.on("paneladded", this.layout, this);
35195 r.on("panelremoved", this.layout, this);
35196 r.on("invalidated", this.layout, this);
35197 r.on("resized", this.onRegionResized, this);
35198 r.on("collapsed", this.onRegionCollapsed, this);
35199 r.on("expanded", this.onRegionExpanded, this);
35203 * Performs a layout update.
35205 layout : function()
35207 if(this.updating) {
35211 // render all the rebions if they have not been done alreayd?
35212 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35213 if(this.regions[region] && !this.regions[region].bodyEl){
35214 this.regions[region].onRender(this.el)
35218 var size = this.getViewSize();
35219 var w = size.width;
35220 var h = size.height;
35225 //var x = 0, y = 0;
35227 var rs = this.regions;
35228 var north = rs["north"];
35229 var south = rs["south"];
35230 var west = rs["west"];
35231 var east = rs["east"];
35232 var center = rs["center"];
35233 //if(this.hideOnLayout){ // not supported anymore
35234 //c.el.setStyle("display", "none");
35236 if(north && north.isVisible()){
35237 var b = north.getBox();
35238 var m = north.getMargins();
35239 b.width = w - (m.left+m.right);
35242 centerY = b.height + b.y + m.bottom;
35243 centerH -= centerY;
35244 north.updateBox(this.safeBox(b));
35246 if(south && south.isVisible()){
35247 var b = south.getBox();
35248 var m = south.getMargins();
35249 b.width = w - (m.left+m.right);
35251 var totalHeight = (b.height + m.top + m.bottom);
35252 b.y = h - totalHeight + m.top;
35253 centerH -= totalHeight;
35254 south.updateBox(this.safeBox(b));
35256 if(west && west.isVisible()){
35257 var b = west.getBox();
35258 var m = west.getMargins();
35259 b.height = centerH - (m.top+m.bottom);
35261 b.y = centerY + m.top;
35262 var totalWidth = (b.width + m.left + m.right);
35263 centerX += totalWidth;
35264 centerW -= totalWidth;
35265 west.updateBox(this.safeBox(b));
35267 if(east && east.isVisible()){
35268 var b = east.getBox();
35269 var m = east.getMargins();
35270 b.height = centerH - (m.top+m.bottom);
35271 var totalWidth = (b.width + m.left + m.right);
35272 b.x = w - totalWidth + m.left;
35273 b.y = centerY + m.top;
35274 centerW -= totalWidth;
35275 east.updateBox(this.safeBox(b));
35278 var m = center.getMargins();
35280 x: centerX + m.left,
35281 y: centerY + m.top,
35282 width: centerW - (m.left+m.right),
35283 height: centerH - (m.top+m.bottom)
35285 //if(this.hideOnLayout){
35286 //center.el.setStyle("display", "block");
35288 center.updateBox(this.safeBox(centerBox));
35291 this.fireEvent("layout", this);
35295 safeBox : function(box){
35296 box.width = Math.max(0, box.width);
35297 box.height = Math.max(0, box.height);
35302 * Adds a ContentPanel (or subclass) to this layout.
35303 * @param {String} target The target region key (north, south, east, west or center).
35304 * @param {Roo.ContentPanel} panel The panel to add
35305 * @return {Roo.ContentPanel} The added panel
35307 add : function(target, panel){
35309 target = target.toLowerCase();
35310 return this.regions[target].add(panel);
35314 * Remove a ContentPanel (or subclass) to this layout.
35315 * @param {String} target The target region key (north, south, east, west or center).
35316 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35317 * @return {Roo.ContentPanel} The removed panel
35319 remove : function(target, panel){
35320 target = target.toLowerCase();
35321 return this.regions[target].remove(panel);
35325 * Searches all regions for a panel with the specified id
35326 * @param {String} panelId
35327 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35329 findPanel : function(panelId){
35330 var rs = this.regions;
35331 for(var target in rs){
35332 if(typeof rs[target] != "function"){
35333 var p = rs[target].getPanel(panelId);
35343 * Searches all regions for a panel with the specified id and activates (shows) it.
35344 * @param {String/ContentPanel} panelId The panels id or the panel itself
35345 * @return {Roo.ContentPanel} The shown panel or null
35347 showPanel : function(panelId) {
35348 var rs = this.regions;
35349 for(var target in rs){
35350 var r = rs[target];
35351 if(typeof r != "function"){
35352 if(r.hasPanel(panelId)){
35353 return r.showPanel(panelId);
35361 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35362 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35365 restoreState : function(provider){
35367 provider = Roo.state.Manager;
35369 var sm = new Roo.LayoutStateManager();
35370 sm.init(this, provider);
35376 * Adds a xtype elements to the layout.
35380 xtype : 'ContentPanel',
35387 xtype : 'NestedLayoutPanel',
35393 items : [ ... list of content panels or nested layout panels.. ]
35397 * @param {Object} cfg Xtype definition of item to add.
35399 addxtype : function(cfg)
35401 // basically accepts a pannel...
35402 // can accept a layout region..!?!?
35403 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35406 // theory? children can only be panels??
35408 //if (!cfg.xtype.match(/Panel$/)) {
35413 if (typeof(cfg.region) == 'undefined') {
35414 Roo.log("Failed to add Panel, region was not set");
35418 var region = cfg.region;
35424 xitems = cfg.items;
35429 if ( region == 'center') {
35430 Roo.log("Center: " + cfg.title);
35436 case 'Content': // ContentPanel (el, cfg)
35437 case 'Scroll': // ContentPanel (el, cfg)
35439 cfg.autoCreate = cfg.autoCreate || true;
35440 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35442 // var el = this.el.createChild();
35443 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35446 this.add(region, ret);
35450 case 'TreePanel': // our new panel!
35451 cfg.el = this.el.createChild();
35452 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35453 this.add(region, ret);
35458 // create a new Layout (which is a Border Layout...
35460 var clayout = cfg.layout;
35461 clayout.el = this.el.createChild();
35462 clayout.items = clayout.items || [];
35466 // replace this exitems with the clayout ones..
35467 xitems = clayout.items;
35469 // force background off if it's in center...
35470 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35471 cfg.background = false;
35473 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35476 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35477 //console.log('adding nested layout panel ' + cfg.toSource());
35478 this.add(region, ret);
35479 nb = {}; /// find first...
35484 // needs grid and region
35486 //var el = this.getRegion(region).el.createChild();
35488 *var el = this.el.createChild();
35489 // create the grid first...
35490 cfg.grid.container = el;
35491 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35494 if (region == 'center' && this.active ) {
35495 cfg.background = false;
35498 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35500 this.add(region, ret);
35502 if (cfg.background) {
35503 // render grid on panel activation (if panel background)
35504 ret.on('activate', function(gp) {
35505 if (!gp.grid.rendered) {
35506 // gp.grid.render(el);
35510 // cfg.grid.render(el);
35516 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35517 // it was the old xcomponent building that caused this before.
35518 // espeically if border is the top element in the tree.
35528 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35530 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35531 this.add(region, ret);
35535 throw "Can not add '" + cfg.xtype + "' to Border";
35541 this.beginUpdate();
35545 Roo.each(xitems, function(i) {
35546 region = nb && i.region ? i.region : false;
35548 var add = ret.addxtype(i);
35551 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35552 if (!i.background) {
35553 abn[region] = nb[region] ;
35560 // make the last non-background panel active..
35561 //if (nb) { Roo.log(abn); }
35564 for(var r in abn) {
35565 region = this.getRegion(r);
35567 // tried using nb[r], but it does not work..
35569 region.showPanel(abn[r]);
35580 factory : function(cfg)
35583 var validRegions = Roo.bootstrap.layout.Border.regions;
35585 var target = cfg.region;
35588 var r = Roo.bootstrap.layout;
35592 return new r.North(cfg);
35594 return new r.South(cfg);
35596 return new r.East(cfg);
35598 return new r.West(cfg);
35600 return new r.Center(cfg);
35602 throw 'Layout region "'+target+'" not supported.';
35609 * Ext JS Library 1.1.1
35610 * Copyright(c) 2006-2007, Ext JS, LLC.
35612 * Originally Released Under LGPL - original licence link has changed is not relivant.
35615 * <script type="text/javascript">
35619 * @class Roo.bootstrap.layout.Basic
35620 * @extends Roo.util.Observable
35621 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35622 * and does not have a titlebar, tabs or any other features. All it does is size and position
35623 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35624 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35625 * @cfg {string} region the region that it inhabits..
35626 * @cfg {bool} skipConfig skip config?
35630 Roo.bootstrap.layout.Basic = function(config){
35632 this.mgr = config.mgr;
35634 this.position = config.region;
35636 var skipConfig = config.skipConfig;
35640 * @scope Roo.BasicLayoutRegion
35644 * @event beforeremove
35645 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35646 * @param {Roo.LayoutRegion} this
35647 * @param {Roo.ContentPanel} panel The panel
35648 * @param {Object} e The cancel event object
35650 "beforeremove" : true,
35652 * @event invalidated
35653 * Fires when the layout for this region is changed.
35654 * @param {Roo.LayoutRegion} this
35656 "invalidated" : true,
35658 * @event visibilitychange
35659 * Fires when this region is shown or hidden
35660 * @param {Roo.LayoutRegion} this
35661 * @param {Boolean} visibility true or false
35663 "visibilitychange" : true,
35665 * @event paneladded
35666 * Fires when a panel is added.
35667 * @param {Roo.LayoutRegion} this
35668 * @param {Roo.ContentPanel} panel The panel
35670 "paneladded" : true,
35672 * @event panelremoved
35673 * Fires when a panel is removed.
35674 * @param {Roo.LayoutRegion} this
35675 * @param {Roo.ContentPanel} panel The panel
35677 "panelremoved" : true,
35679 * @event beforecollapse
35680 * Fires when this region before collapse.
35681 * @param {Roo.LayoutRegion} this
35683 "beforecollapse" : true,
35686 * Fires when this region is collapsed.
35687 * @param {Roo.LayoutRegion} this
35689 "collapsed" : true,
35692 * Fires when this region is expanded.
35693 * @param {Roo.LayoutRegion} this
35698 * Fires when this region is slid into view.
35699 * @param {Roo.LayoutRegion} this
35701 "slideshow" : true,
35704 * Fires when this region slides out of view.
35705 * @param {Roo.LayoutRegion} this
35707 "slidehide" : true,
35709 * @event panelactivated
35710 * Fires when a panel is activated.
35711 * @param {Roo.LayoutRegion} this
35712 * @param {Roo.ContentPanel} panel The activated panel
35714 "panelactivated" : true,
35717 * Fires when the user resizes this region.
35718 * @param {Roo.LayoutRegion} this
35719 * @param {Number} newSize The new size (width for east/west, height for north/south)
35723 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35724 this.panels = new Roo.util.MixedCollection();
35725 this.panels.getKey = this.getPanelId.createDelegate(this);
35727 this.activePanel = null;
35728 // ensure listeners are added...
35730 if (config.listeners || config.events) {
35731 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35732 listeners : config.listeners || {},
35733 events : config.events || {}
35737 if(skipConfig !== true){
35738 this.applyConfig(config);
35742 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35744 getPanelId : function(p){
35748 applyConfig : function(config){
35749 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35750 this.config = config;
35755 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35756 * the width, for horizontal (north, south) the height.
35757 * @param {Number} newSize The new width or height
35759 resizeTo : function(newSize){
35760 var el = this.el ? this.el :
35761 (this.activePanel ? this.activePanel.getEl() : null);
35763 switch(this.position){
35766 el.setWidth(newSize);
35767 this.fireEvent("resized", this, newSize);
35771 el.setHeight(newSize);
35772 this.fireEvent("resized", this, newSize);
35778 getBox : function(){
35779 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35782 getMargins : function(){
35783 return this.margins;
35786 updateBox : function(box){
35788 var el = this.activePanel.getEl();
35789 el.dom.style.left = box.x + "px";
35790 el.dom.style.top = box.y + "px";
35791 this.activePanel.setSize(box.width, box.height);
35795 * Returns the container element for this region.
35796 * @return {Roo.Element}
35798 getEl : function(){
35799 return this.activePanel;
35803 * Returns true if this region is currently visible.
35804 * @return {Boolean}
35806 isVisible : function(){
35807 return this.activePanel ? true : false;
35810 setActivePanel : function(panel){
35811 panel = this.getPanel(panel);
35812 if(this.activePanel && this.activePanel != panel){
35813 this.activePanel.setActiveState(false);
35814 this.activePanel.getEl().setLeftTop(-10000,-10000);
35816 this.activePanel = panel;
35817 panel.setActiveState(true);
35819 panel.setSize(this.box.width, this.box.height);
35821 this.fireEvent("panelactivated", this, panel);
35822 this.fireEvent("invalidated");
35826 * Show the specified panel.
35827 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35828 * @return {Roo.ContentPanel} The shown panel or null
35830 showPanel : function(panel){
35831 panel = this.getPanel(panel);
35833 this.setActivePanel(panel);
35839 * Get the active panel for this region.
35840 * @return {Roo.ContentPanel} The active panel or null
35842 getActivePanel : function(){
35843 return this.activePanel;
35847 * Add the passed ContentPanel(s)
35848 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35849 * @return {Roo.ContentPanel} The panel added (if only one was added)
35851 add : function(panel){
35852 if(arguments.length > 1){
35853 for(var i = 0, len = arguments.length; i < len; i++) {
35854 this.add(arguments[i]);
35858 if(this.hasPanel(panel)){
35859 this.showPanel(panel);
35862 var el = panel.getEl();
35863 if(el.dom.parentNode != this.mgr.el.dom){
35864 this.mgr.el.dom.appendChild(el.dom);
35866 if(panel.setRegion){
35867 panel.setRegion(this);
35869 this.panels.add(panel);
35870 el.setStyle("position", "absolute");
35871 if(!panel.background){
35872 this.setActivePanel(panel);
35873 if(this.config.initialSize && this.panels.getCount()==1){
35874 this.resizeTo(this.config.initialSize);
35877 this.fireEvent("paneladded", this, panel);
35882 * Returns true if the panel is in this region.
35883 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35884 * @return {Boolean}
35886 hasPanel : function(panel){
35887 if(typeof panel == "object"){ // must be panel obj
35888 panel = panel.getId();
35890 return this.getPanel(panel) ? true : false;
35894 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35895 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35896 * @param {Boolean} preservePanel Overrides the config preservePanel option
35897 * @return {Roo.ContentPanel} The panel that was removed
35899 remove : function(panel, preservePanel){
35900 panel = this.getPanel(panel);
35905 this.fireEvent("beforeremove", this, panel, e);
35906 if(e.cancel === true){
35909 var panelId = panel.getId();
35910 this.panels.removeKey(panelId);
35915 * Returns the panel specified or null if it's not in this region.
35916 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35917 * @return {Roo.ContentPanel}
35919 getPanel : function(id){
35920 if(typeof id == "object"){ // must be panel obj
35923 return this.panels.get(id);
35927 * Returns this regions position (north/south/east/west/center).
35930 getPosition: function(){
35931 return this.position;
35935 * Ext JS Library 1.1.1
35936 * Copyright(c) 2006-2007, Ext JS, LLC.
35938 * Originally Released Under LGPL - original licence link has changed is not relivant.
35941 * <script type="text/javascript">
35945 * @class Roo.bootstrap.layout.Region
35946 * @extends Roo.bootstrap.layout.Basic
35947 * This class represents a region in a layout manager.
35949 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35950 * @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})
35951 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35952 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35953 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35954 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35955 * @cfg {String} title The title for the region (overrides panel titles)
35956 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35957 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35958 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35959 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35960 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35961 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35962 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35963 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35964 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35965 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35967 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35968 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35969 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35970 * @cfg {Number} width For East/West panels
35971 * @cfg {Number} height For North/South panels
35972 * @cfg {Boolean} split To show the splitter
35973 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35975 * @cfg {string} cls Extra CSS classes to add to region
35977 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35978 * @cfg {string} region the region that it inhabits..
35981 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35982 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35984 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35985 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35986 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35988 Roo.bootstrap.layout.Region = function(config)
35990 this.applyConfig(config);
35992 var mgr = config.mgr;
35993 var pos = config.region;
35994 config.skipConfig = true;
35995 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35998 this.onRender(mgr.el);
36001 this.visible = true;
36002 this.collapsed = false;
36003 this.unrendered_panels = [];
36006 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
36008 position: '', // set by wrapper (eg. north/south etc..)
36009 unrendered_panels : null, // unrendered panels.
36011 tabPosition : false,
36013 mgr: false, // points to 'Border'
36016 createBody : function(){
36017 /** This region's body element
36018 * @type Roo.Element */
36019 this.bodyEl = this.el.createChild({
36021 cls: "roo-layout-panel-body tab-content" // bootstrap added...
36025 onRender: function(ctr, pos)
36027 var dh = Roo.DomHelper;
36028 /** This region's container element
36029 * @type Roo.Element */
36030 this.el = dh.append(ctr.dom, {
36032 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
36034 /** This region's title element
36035 * @type Roo.Element */
36037 this.titleEl = dh.append(this.el.dom, {
36039 unselectable: "on",
36040 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36042 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36043 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36047 this.titleEl.enableDisplayMode();
36048 /** This region's title text element
36049 * @type HTMLElement */
36050 this.titleTextEl = this.titleEl.dom.firstChild;
36051 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36053 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36054 this.closeBtn.enableDisplayMode();
36055 this.closeBtn.on("click", this.closeClicked, this);
36056 this.closeBtn.hide();
36058 this.createBody(this.config);
36059 if(this.config.hideWhenEmpty){
36061 this.on("paneladded", this.validateVisibility, this);
36062 this.on("panelremoved", this.validateVisibility, this);
36064 if(this.autoScroll){
36065 this.bodyEl.setStyle("overflow", "auto");
36067 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36069 //if(c.titlebar !== false){
36070 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36071 this.titleEl.hide();
36073 this.titleEl.show();
36074 if(this.config.title){
36075 this.titleTextEl.innerHTML = this.config.title;
36079 if(this.config.collapsed){
36080 this.collapse(true);
36082 if(this.config.hidden){
36086 if (this.unrendered_panels && this.unrendered_panels.length) {
36087 for (var i =0;i< this.unrendered_panels.length; i++) {
36088 this.add(this.unrendered_panels[i]);
36090 this.unrendered_panels = null;
36096 applyConfig : function(c)
36099 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36100 var dh = Roo.DomHelper;
36101 if(c.titlebar !== false){
36102 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36103 this.collapseBtn.on("click", this.collapse, this);
36104 this.collapseBtn.enableDisplayMode();
36106 if(c.showPin === true || this.showPin){
36107 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36108 this.stickBtn.enableDisplayMode();
36109 this.stickBtn.on("click", this.expand, this);
36110 this.stickBtn.hide();
36115 /** This region's collapsed element
36116 * @type Roo.Element */
36119 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36120 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36123 if(c.floatable !== false){
36124 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36125 this.collapsedEl.on("click", this.collapseClick, this);
36128 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36129 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36130 id: "message", unselectable: "on", style:{"float":"left"}});
36131 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36133 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36134 this.expandBtn.on("click", this.expand, this);
36138 if(this.collapseBtn){
36139 this.collapseBtn.setVisible(c.collapsible == true);
36142 this.cmargins = c.cmargins || this.cmargins ||
36143 (this.position == "west" || this.position == "east" ?
36144 {top: 0, left: 2, right:2, bottom: 0} :
36145 {top: 2, left: 0, right:0, bottom: 2});
36147 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36150 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36152 this.autoScroll = c.autoScroll || false;
36157 this.duration = c.duration || .30;
36158 this.slideDuration = c.slideDuration || .45;
36163 * Returns true if this region is currently visible.
36164 * @return {Boolean}
36166 isVisible : function(){
36167 return this.visible;
36171 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36172 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36174 //setCollapsedTitle : function(title){
36175 // title = title || " ";
36176 // if(this.collapsedTitleTextEl){
36177 // this.collapsedTitleTextEl.innerHTML = title;
36181 getBox : function(){
36183 // if(!this.collapsed){
36184 b = this.el.getBox(false, true);
36186 // b = this.collapsedEl.getBox(false, true);
36191 getMargins : function(){
36192 return this.margins;
36193 //return this.collapsed ? this.cmargins : this.margins;
36196 highlight : function(){
36197 this.el.addClass("x-layout-panel-dragover");
36200 unhighlight : function(){
36201 this.el.removeClass("x-layout-panel-dragover");
36204 updateBox : function(box)
36206 if (!this.bodyEl) {
36207 return; // not rendered yet..
36211 if(!this.collapsed){
36212 this.el.dom.style.left = box.x + "px";
36213 this.el.dom.style.top = box.y + "px";
36214 this.updateBody(box.width, box.height);
36216 this.collapsedEl.dom.style.left = box.x + "px";
36217 this.collapsedEl.dom.style.top = box.y + "px";
36218 this.collapsedEl.setSize(box.width, box.height);
36221 this.tabs.autoSizeTabs();
36225 updateBody : function(w, h)
36228 this.el.setWidth(w);
36229 w -= this.el.getBorderWidth("rl");
36230 if(this.config.adjustments){
36231 w += this.config.adjustments[0];
36234 if(h !== null && h > 0){
36235 this.el.setHeight(h);
36236 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36237 h -= this.el.getBorderWidth("tb");
36238 if(this.config.adjustments){
36239 h += this.config.adjustments[1];
36241 this.bodyEl.setHeight(h);
36243 h = this.tabs.syncHeight(h);
36246 if(this.panelSize){
36247 w = w !== null ? w : this.panelSize.width;
36248 h = h !== null ? h : this.panelSize.height;
36250 if(this.activePanel){
36251 var el = this.activePanel.getEl();
36252 w = w !== null ? w : el.getWidth();
36253 h = h !== null ? h : el.getHeight();
36254 this.panelSize = {width: w, height: h};
36255 this.activePanel.setSize(w, h);
36257 if(Roo.isIE && this.tabs){
36258 this.tabs.el.repaint();
36263 * Returns the container element for this region.
36264 * @return {Roo.Element}
36266 getEl : function(){
36271 * Hides this region.
36274 //if(!this.collapsed){
36275 this.el.dom.style.left = "-2000px";
36278 // this.collapsedEl.dom.style.left = "-2000px";
36279 // this.collapsedEl.hide();
36281 this.visible = false;
36282 this.fireEvent("visibilitychange", this, false);
36286 * Shows this region if it was previously hidden.
36289 //if(!this.collapsed){
36292 // this.collapsedEl.show();
36294 this.visible = true;
36295 this.fireEvent("visibilitychange", this, true);
36298 closeClicked : function(){
36299 if(this.activePanel){
36300 this.remove(this.activePanel);
36304 collapseClick : function(e){
36306 e.stopPropagation();
36309 e.stopPropagation();
36315 * Collapses this region.
36316 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36319 collapse : function(skipAnim, skipCheck = false){
36320 if(this.collapsed) {
36324 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36326 this.collapsed = true;
36328 this.split.el.hide();
36330 if(this.config.animate && skipAnim !== true){
36331 this.fireEvent("invalidated", this);
36332 this.animateCollapse();
36334 this.el.setLocation(-20000,-20000);
36336 this.collapsedEl.show();
36337 this.fireEvent("collapsed", this);
36338 this.fireEvent("invalidated", this);
36344 animateCollapse : function(){
36349 * Expands this region if it was previously collapsed.
36350 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36351 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36354 expand : function(e, skipAnim){
36356 e.stopPropagation();
36358 if(!this.collapsed || this.el.hasActiveFx()) {
36362 this.afterSlideIn();
36365 this.collapsed = false;
36366 if(this.config.animate && skipAnim !== true){
36367 this.animateExpand();
36371 this.split.el.show();
36373 this.collapsedEl.setLocation(-2000,-2000);
36374 this.collapsedEl.hide();
36375 this.fireEvent("invalidated", this);
36376 this.fireEvent("expanded", this);
36380 animateExpand : function(){
36384 initTabs : function()
36386 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36388 var ts = new Roo.bootstrap.panel.Tabs({
36389 el: this.bodyEl.dom,
36391 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36392 disableTooltips: this.config.disableTabTips,
36393 toolbar : this.config.toolbar
36396 if(this.config.hideTabs){
36397 ts.stripWrap.setDisplayed(false);
36400 ts.resizeTabs = this.config.resizeTabs === true;
36401 ts.minTabWidth = this.config.minTabWidth || 40;
36402 ts.maxTabWidth = this.config.maxTabWidth || 250;
36403 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36404 ts.monitorResize = false;
36405 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36406 ts.bodyEl.addClass('roo-layout-tabs-body');
36407 this.panels.each(this.initPanelAsTab, this);
36410 initPanelAsTab : function(panel){
36411 var ti = this.tabs.addTab(
36415 this.config.closeOnTab && panel.isClosable(),
36418 if(panel.tabTip !== undefined){
36419 ti.setTooltip(panel.tabTip);
36421 ti.on("activate", function(){
36422 this.setActivePanel(panel);
36425 if(this.config.closeOnTab){
36426 ti.on("beforeclose", function(t, e){
36428 this.remove(panel);
36432 panel.tabItem = ti;
36437 updatePanelTitle : function(panel, title)
36439 if(this.activePanel == panel){
36440 this.updateTitle(title);
36443 var ti = this.tabs.getTab(panel.getEl().id);
36445 if(panel.tabTip !== undefined){
36446 ti.setTooltip(panel.tabTip);
36451 updateTitle : function(title){
36452 if(this.titleTextEl && !this.config.title){
36453 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36457 setActivePanel : function(panel)
36459 panel = this.getPanel(panel);
36460 if(this.activePanel && this.activePanel != panel){
36461 if(this.activePanel.setActiveState(false) === false){
36465 this.activePanel = panel;
36466 panel.setActiveState(true);
36467 if(this.panelSize){
36468 panel.setSize(this.panelSize.width, this.panelSize.height);
36471 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36473 this.updateTitle(panel.getTitle());
36475 this.fireEvent("invalidated", this);
36477 this.fireEvent("panelactivated", this, panel);
36481 * Shows the specified panel.
36482 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36483 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36485 showPanel : function(panel)
36487 panel = this.getPanel(panel);
36490 var tab = this.tabs.getTab(panel.getEl().id);
36491 if(tab.isHidden()){
36492 this.tabs.unhideTab(tab.id);
36496 this.setActivePanel(panel);
36503 * Get the active panel for this region.
36504 * @return {Roo.ContentPanel} The active panel or null
36506 getActivePanel : function(){
36507 return this.activePanel;
36510 validateVisibility : function(){
36511 if(this.panels.getCount() < 1){
36512 this.updateTitle(" ");
36513 this.closeBtn.hide();
36516 if(!this.isVisible()){
36523 * Adds the passed ContentPanel(s) to this region.
36524 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36525 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36527 add : function(panel)
36529 if(arguments.length > 1){
36530 for(var i = 0, len = arguments.length; i < len; i++) {
36531 this.add(arguments[i]);
36536 // if we have not been rendered yet, then we can not really do much of this..
36537 if (!this.bodyEl) {
36538 this.unrendered_panels.push(panel);
36545 if(this.hasPanel(panel)){
36546 this.showPanel(panel);
36549 panel.setRegion(this);
36550 this.panels.add(panel);
36551 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36552 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36553 // and hide them... ???
36554 this.bodyEl.dom.appendChild(panel.getEl().dom);
36555 if(panel.background !== true){
36556 this.setActivePanel(panel);
36558 this.fireEvent("paneladded", this, panel);
36565 this.initPanelAsTab(panel);
36569 if(panel.background !== true){
36570 this.tabs.activate(panel.getEl().id);
36572 this.fireEvent("paneladded", this, panel);
36577 * Hides the tab for the specified panel.
36578 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36580 hidePanel : function(panel){
36581 if(this.tabs && (panel = this.getPanel(panel))){
36582 this.tabs.hideTab(panel.getEl().id);
36587 * Unhides the tab for a previously hidden panel.
36588 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36590 unhidePanel : function(panel){
36591 if(this.tabs && (panel = this.getPanel(panel))){
36592 this.tabs.unhideTab(panel.getEl().id);
36596 clearPanels : function(){
36597 while(this.panels.getCount() > 0){
36598 this.remove(this.panels.first());
36603 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36604 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36605 * @param {Boolean} preservePanel Overrides the config preservePanel option
36606 * @return {Roo.ContentPanel} The panel that was removed
36608 remove : function(panel, preservePanel)
36610 panel = this.getPanel(panel);
36615 this.fireEvent("beforeremove", this, panel, e);
36616 if(e.cancel === true){
36619 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36620 var panelId = panel.getId();
36621 this.panels.removeKey(panelId);
36623 document.body.appendChild(panel.getEl().dom);
36626 this.tabs.removeTab(panel.getEl().id);
36627 }else if (!preservePanel){
36628 this.bodyEl.dom.removeChild(panel.getEl().dom);
36630 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36631 var p = this.panels.first();
36632 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36633 tempEl.appendChild(p.getEl().dom);
36634 this.bodyEl.update("");
36635 this.bodyEl.dom.appendChild(p.getEl().dom);
36637 this.updateTitle(p.getTitle());
36639 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36640 this.setActivePanel(p);
36642 panel.setRegion(null);
36643 if(this.activePanel == panel){
36644 this.activePanel = null;
36646 if(this.config.autoDestroy !== false && preservePanel !== true){
36647 try{panel.destroy();}catch(e){}
36649 this.fireEvent("panelremoved", this, panel);
36654 * Returns the TabPanel component used by this region
36655 * @return {Roo.TabPanel}
36657 getTabs : function(){
36661 createTool : function(parentEl, className){
36662 var btn = Roo.DomHelper.append(parentEl, {
36664 cls: "x-layout-tools-button",
36667 cls: "roo-layout-tools-button-inner " + className,
36671 btn.addClassOnOver("roo-layout-tools-button-over");
36676 * Ext JS Library 1.1.1
36677 * Copyright(c) 2006-2007, Ext JS, LLC.
36679 * Originally Released Under LGPL - original licence link has changed is not relivant.
36682 * <script type="text/javascript">
36688 * @class Roo.SplitLayoutRegion
36689 * @extends Roo.LayoutRegion
36690 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36692 Roo.bootstrap.layout.Split = function(config){
36693 this.cursor = config.cursor;
36694 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36697 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36699 splitTip : "Drag to resize.",
36700 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36701 useSplitTips : false,
36703 applyConfig : function(config){
36704 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36707 onRender : function(ctr,pos) {
36709 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36710 if(!this.config.split){
36715 var splitEl = Roo.DomHelper.append(ctr.dom, {
36717 id: this.el.id + "-split",
36718 cls: "roo-layout-split roo-layout-split-"+this.position,
36721 /** The SplitBar for this region
36722 * @type Roo.SplitBar */
36723 // does not exist yet...
36724 Roo.log([this.position, this.orientation]);
36726 this.split = new Roo.bootstrap.SplitBar({
36727 dragElement : splitEl,
36728 resizingElement: this.el,
36729 orientation : this.orientation
36732 this.split.on("moved", this.onSplitMove, this);
36733 this.split.useShim = this.config.useShim === true;
36734 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36735 if(this.useSplitTips){
36736 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36738 //if(config.collapsible){
36739 // this.split.el.on("dblclick", this.collapse, this);
36742 if(typeof this.config.minSize != "undefined"){
36743 this.split.minSize = this.config.minSize;
36745 if(typeof this.config.maxSize != "undefined"){
36746 this.split.maxSize = this.config.maxSize;
36748 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36749 this.hideSplitter();
36754 getHMaxSize : function(){
36755 var cmax = this.config.maxSize || 10000;
36756 var center = this.mgr.getRegion("center");
36757 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36760 getVMaxSize : function(){
36761 var cmax = this.config.maxSize || 10000;
36762 var center = this.mgr.getRegion("center");
36763 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36766 onSplitMove : function(split, newSize){
36767 this.fireEvent("resized", this, newSize);
36771 * Returns the {@link Roo.SplitBar} for this region.
36772 * @return {Roo.SplitBar}
36774 getSplitBar : function(){
36779 this.hideSplitter();
36780 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36783 hideSplitter : function(){
36785 this.split.el.setLocation(-2000,-2000);
36786 this.split.el.hide();
36792 this.split.el.show();
36794 Roo.bootstrap.layout.Split.superclass.show.call(this);
36797 beforeSlide: function(){
36798 if(Roo.isGecko){// firefox overflow auto bug workaround
36799 this.bodyEl.clip();
36801 this.tabs.bodyEl.clip();
36803 if(this.activePanel){
36804 this.activePanel.getEl().clip();
36806 if(this.activePanel.beforeSlide){
36807 this.activePanel.beforeSlide();
36813 afterSlide : function(){
36814 if(Roo.isGecko){// firefox overflow auto bug workaround
36815 this.bodyEl.unclip();
36817 this.tabs.bodyEl.unclip();
36819 if(this.activePanel){
36820 this.activePanel.getEl().unclip();
36821 if(this.activePanel.afterSlide){
36822 this.activePanel.afterSlide();
36828 initAutoHide : function(){
36829 if(this.autoHide !== false){
36830 if(!this.autoHideHd){
36831 var st = new Roo.util.DelayedTask(this.slideIn, this);
36832 this.autoHideHd = {
36833 "mouseout": function(e){
36834 if(!e.within(this.el, true)){
36838 "mouseover" : function(e){
36844 this.el.on(this.autoHideHd);
36848 clearAutoHide : function(){
36849 if(this.autoHide !== false){
36850 this.el.un("mouseout", this.autoHideHd.mouseout);
36851 this.el.un("mouseover", this.autoHideHd.mouseover);
36855 clearMonitor : function(){
36856 Roo.get(document).un("click", this.slideInIf, this);
36859 // these names are backwards but not changed for compat
36860 slideOut : function(){
36861 if(this.isSlid || this.el.hasActiveFx()){
36864 this.isSlid = true;
36865 if(this.collapseBtn){
36866 this.collapseBtn.hide();
36868 this.closeBtnState = this.closeBtn.getStyle('display');
36869 this.closeBtn.hide();
36871 this.stickBtn.show();
36874 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36875 this.beforeSlide();
36876 this.el.setStyle("z-index", 10001);
36877 this.el.slideIn(this.getSlideAnchor(), {
36878 callback: function(){
36880 this.initAutoHide();
36881 Roo.get(document).on("click", this.slideInIf, this);
36882 this.fireEvent("slideshow", this);
36889 afterSlideIn : function(){
36890 this.clearAutoHide();
36891 this.isSlid = false;
36892 this.clearMonitor();
36893 this.el.setStyle("z-index", "");
36894 if(this.collapseBtn){
36895 this.collapseBtn.show();
36897 this.closeBtn.setStyle('display', this.closeBtnState);
36899 this.stickBtn.hide();
36901 this.fireEvent("slidehide", this);
36904 slideIn : function(cb){
36905 if(!this.isSlid || this.el.hasActiveFx()){
36909 this.isSlid = false;
36910 this.beforeSlide();
36911 this.el.slideOut(this.getSlideAnchor(), {
36912 callback: function(){
36913 this.el.setLeftTop(-10000, -10000);
36915 this.afterSlideIn();
36923 slideInIf : function(e){
36924 if(!e.within(this.el)){
36929 animateCollapse : function(){
36930 this.beforeSlide();
36931 this.el.setStyle("z-index", 20000);
36932 var anchor = this.getSlideAnchor();
36933 this.el.slideOut(anchor, {
36934 callback : function(){
36935 this.el.setStyle("z-index", "");
36936 this.collapsedEl.slideIn(anchor, {duration:.3});
36938 this.el.setLocation(-10000,-10000);
36940 this.fireEvent("collapsed", this);
36947 animateExpand : function(){
36948 this.beforeSlide();
36949 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36950 this.el.setStyle("z-index", 20000);
36951 this.collapsedEl.hide({
36954 this.el.slideIn(this.getSlideAnchor(), {
36955 callback : function(){
36956 this.el.setStyle("z-index", "");
36959 this.split.el.show();
36961 this.fireEvent("invalidated", this);
36962 this.fireEvent("expanded", this);
36990 getAnchor : function(){
36991 return this.anchors[this.position];
36994 getCollapseAnchor : function(){
36995 return this.canchors[this.position];
36998 getSlideAnchor : function(){
36999 return this.sanchors[this.position];
37002 getAlignAdj : function(){
37003 var cm = this.cmargins;
37004 switch(this.position){
37020 getExpandAdj : function(){
37021 var c = this.collapsedEl, cm = this.cmargins;
37022 switch(this.position){
37024 return [-(cm.right+c.getWidth()+cm.left), 0];
37027 return [cm.right+c.getWidth()+cm.left, 0];
37030 return [0, -(cm.top+cm.bottom+c.getHeight())];
37033 return [0, cm.top+cm.bottom+c.getHeight()];
37039 * Ext JS Library 1.1.1
37040 * Copyright(c) 2006-2007, Ext JS, LLC.
37042 * Originally Released Under LGPL - original licence link has changed is not relivant.
37045 * <script type="text/javascript">
37048 * These classes are private internal classes
37050 Roo.bootstrap.layout.Center = function(config){
37051 config.region = "center";
37052 Roo.bootstrap.layout.Region.call(this, config);
37053 this.visible = true;
37054 this.minWidth = config.minWidth || 20;
37055 this.minHeight = config.minHeight || 20;
37058 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37060 // center panel can't be hidden
37064 // center panel can't be hidden
37067 getMinWidth: function(){
37068 return this.minWidth;
37071 getMinHeight: function(){
37072 return this.minHeight;
37086 Roo.bootstrap.layout.North = function(config)
37088 config.region = 'north';
37089 config.cursor = 'n-resize';
37091 Roo.bootstrap.layout.Split.call(this, config);
37095 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37096 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37097 this.split.el.addClass("roo-layout-split-v");
37099 var size = config.initialSize || config.height;
37100 if(typeof size != "undefined"){
37101 this.el.setHeight(size);
37104 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37106 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37110 getBox : function(){
37111 if(this.collapsed){
37112 return this.collapsedEl.getBox();
37114 var box = this.el.getBox();
37116 box.height += this.split.el.getHeight();
37121 updateBox : function(box){
37122 if(this.split && !this.collapsed){
37123 box.height -= this.split.el.getHeight();
37124 this.split.el.setLeft(box.x);
37125 this.split.el.setTop(box.y+box.height);
37126 this.split.el.setWidth(box.width);
37128 if(this.collapsed){
37129 this.updateBody(box.width, null);
37131 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37139 Roo.bootstrap.layout.South = function(config){
37140 config.region = 'south';
37141 config.cursor = 's-resize';
37142 Roo.bootstrap.layout.Split.call(this, config);
37144 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37145 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37146 this.split.el.addClass("roo-layout-split-v");
37148 var size = config.initialSize || config.height;
37149 if(typeof size != "undefined"){
37150 this.el.setHeight(size);
37154 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37155 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37156 getBox : function(){
37157 if(this.collapsed){
37158 return this.collapsedEl.getBox();
37160 var box = this.el.getBox();
37162 var sh = this.split.el.getHeight();
37169 updateBox : function(box){
37170 if(this.split && !this.collapsed){
37171 var sh = this.split.el.getHeight();
37174 this.split.el.setLeft(box.x);
37175 this.split.el.setTop(box.y-sh);
37176 this.split.el.setWidth(box.width);
37178 if(this.collapsed){
37179 this.updateBody(box.width, null);
37181 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37185 Roo.bootstrap.layout.East = function(config){
37186 config.region = "east";
37187 config.cursor = "e-resize";
37188 Roo.bootstrap.layout.Split.call(this, config);
37190 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37191 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37192 this.split.el.addClass("roo-layout-split-h");
37194 var size = config.initialSize || config.width;
37195 if(typeof size != "undefined"){
37196 this.el.setWidth(size);
37199 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37200 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37201 getBox : function(){
37202 if(this.collapsed){
37203 return this.collapsedEl.getBox();
37205 var box = this.el.getBox();
37207 var sw = this.split.el.getWidth();
37214 updateBox : function(box){
37215 if(this.split && !this.collapsed){
37216 var sw = this.split.el.getWidth();
37218 this.split.el.setLeft(box.x);
37219 this.split.el.setTop(box.y);
37220 this.split.el.setHeight(box.height);
37223 if(this.collapsed){
37224 this.updateBody(null, box.height);
37226 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37230 Roo.bootstrap.layout.West = function(config){
37231 config.region = "west";
37232 config.cursor = "w-resize";
37234 Roo.bootstrap.layout.Split.call(this, config);
37236 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37237 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37238 this.split.el.addClass("roo-layout-split-h");
37242 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37243 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37245 onRender: function(ctr, pos)
37247 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37248 var size = this.config.initialSize || this.config.width;
37249 if(typeof size != "undefined"){
37250 this.el.setWidth(size);
37254 getBox : function(){
37255 if(this.collapsed){
37256 return this.collapsedEl.getBox();
37258 var box = this.el.getBox();
37260 box.width += this.split.el.getWidth();
37265 updateBox : function(box){
37266 if(this.split && !this.collapsed){
37267 var sw = this.split.el.getWidth();
37269 this.split.el.setLeft(box.x+box.width);
37270 this.split.el.setTop(box.y);
37271 this.split.el.setHeight(box.height);
37273 if(this.collapsed){
37274 this.updateBody(null, box.height);
37276 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37278 });Roo.namespace("Roo.bootstrap.panel");/*
37280 * Ext JS Library 1.1.1
37281 * Copyright(c) 2006-2007, Ext JS, LLC.
37283 * Originally Released Under LGPL - original licence link has changed is not relivant.
37286 * <script type="text/javascript">
37289 * @class Roo.ContentPanel
37290 * @extends Roo.util.Observable
37291 * A basic ContentPanel element.
37292 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37293 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37294 * @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
37295 * @cfg {Boolean} closable True if the panel can be closed/removed
37296 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37297 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37298 * @cfg {Toolbar} toolbar A toolbar for this panel
37299 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37300 * @cfg {String} title The title for this panel
37301 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37302 * @cfg {String} url Calls {@link #setUrl} with this value
37303 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37304 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37305 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37306 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37307 * @cfg {Boolean} badges render the badges
37310 * Create a new ContentPanel.
37311 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37312 * @param {String/Object} config A string to set only the title or a config object
37313 * @param {String} content (optional) Set the HTML content for this panel
37314 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37316 Roo.bootstrap.panel.Content = function( config){
37318 this.tpl = config.tpl || false;
37320 var el = config.el;
37321 var content = config.content;
37323 if(config.autoCreate){ // xtype is available if this is called from factory
37326 this.el = Roo.get(el);
37327 if(!this.el && config && config.autoCreate){
37328 if(typeof config.autoCreate == "object"){
37329 if(!config.autoCreate.id){
37330 config.autoCreate.id = config.id||el;
37332 this.el = Roo.DomHelper.append(document.body,
37333 config.autoCreate, true);
37335 var elcfg = { tag: "div",
37336 cls: "roo-layout-inactive-content",
37340 elcfg.html = config.html;
37344 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37347 this.closable = false;
37348 this.loaded = false;
37349 this.active = false;
37352 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37354 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37356 this.wrapEl = this.el; //this.el.wrap();
37358 if (config.toolbar.items) {
37359 ti = config.toolbar.items ;
37360 delete config.toolbar.items ;
37364 this.toolbar.render(this.wrapEl, 'before');
37365 for(var i =0;i < ti.length;i++) {
37366 // Roo.log(['add child', items[i]]);
37367 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37369 this.toolbar.items = nitems;
37370 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37371 delete config.toolbar;
37375 // xtype created footer. - not sure if will work as we normally have to render first..
37376 if (this.footer && !this.footer.el && this.footer.xtype) {
37377 if (!this.wrapEl) {
37378 this.wrapEl = this.el.wrap();
37381 this.footer.container = this.wrapEl.createChild();
37383 this.footer = Roo.factory(this.footer, Roo);
37388 if(typeof config == "string"){
37389 this.title = config;
37391 Roo.apply(this, config);
37395 this.resizeEl = Roo.get(this.resizeEl, true);
37397 this.resizeEl = this.el;
37399 // handle view.xtype
37407 * Fires when this panel is activated.
37408 * @param {Roo.ContentPanel} this
37412 * @event deactivate
37413 * Fires when this panel is activated.
37414 * @param {Roo.ContentPanel} this
37416 "deactivate" : true,
37420 * Fires when this panel is resized if fitToFrame is true.
37421 * @param {Roo.ContentPanel} this
37422 * @param {Number} width The width after any component adjustments
37423 * @param {Number} height The height after any component adjustments
37429 * Fires when this tab is created
37430 * @param {Roo.ContentPanel} this
37441 if(this.autoScroll){
37442 this.resizeEl.setStyle("overflow", "auto");
37444 // fix randome scrolling
37445 //this.el.on('scroll', function() {
37446 // Roo.log('fix random scolling');
37447 // this.scrollTo('top',0);
37450 content = content || this.content;
37452 this.setContent(content);
37454 if(config && config.url){
37455 this.setUrl(this.url, this.params, this.loadOnce);
37460 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37462 if (this.view && typeof(this.view.xtype) != 'undefined') {
37463 this.view.el = this.el.appendChild(document.createElement("div"));
37464 this.view = Roo.factory(this.view);
37465 this.view.render && this.view.render(false, '');
37469 this.fireEvent('render', this);
37472 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37476 setRegion : function(region){
37477 this.region = region;
37478 this.setActiveClass(region && !this.background);
37482 setActiveClass: function(state)
37485 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37486 this.el.setStyle('position','relative');
37488 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37489 this.el.setStyle('position', 'absolute');
37494 * Returns the toolbar for this Panel if one was configured.
37495 * @return {Roo.Toolbar}
37497 getToolbar : function(){
37498 return this.toolbar;
37501 setActiveState : function(active)
37503 this.active = active;
37504 this.setActiveClass(active);
37506 if(this.fireEvent("deactivate", this) === false){
37511 this.fireEvent("activate", this);
37515 * Updates this panel's element
37516 * @param {String} content The new content
37517 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37519 setContent : function(content, loadScripts){
37520 this.el.update(content, loadScripts);
37523 ignoreResize : function(w, h){
37524 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37527 this.lastSize = {width: w, height: h};
37532 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37533 * @return {Roo.UpdateManager} The UpdateManager
37535 getUpdateManager : function(){
37536 return this.el.getUpdateManager();
37539 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37540 * @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:
37543 url: "your-url.php",
37544 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37545 callback: yourFunction,
37546 scope: yourObject, //(optional scope)
37549 text: "Loading...",
37554 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37555 * 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.
37556 * @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}
37557 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37558 * @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.
37559 * @return {Roo.ContentPanel} this
37562 var um = this.el.getUpdateManager();
37563 um.update.apply(um, arguments);
37569 * 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.
37570 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37571 * @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)
37572 * @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)
37573 * @return {Roo.UpdateManager} The UpdateManager
37575 setUrl : function(url, params, loadOnce){
37576 if(this.refreshDelegate){
37577 this.removeListener("activate", this.refreshDelegate);
37579 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37580 this.on("activate", this.refreshDelegate);
37581 return this.el.getUpdateManager();
37584 _handleRefresh : function(url, params, loadOnce){
37585 if(!loadOnce || !this.loaded){
37586 var updater = this.el.getUpdateManager();
37587 updater.update(url, params, this._setLoaded.createDelegate(this));
37591 _setLoaded : function(){
37592 this.loaded = true;
37596 * Returns this panel's id
37599 getId : function(){
37604 * Returns this panel's element - used by regiosn to add.
37605 * @return {Roo.Element}
37607 getEl : function(){
37608 return this.wrapEl || this.el;
37613 adjustForComponents : function(width, height)
37615 //Roo.log('adjustForComponents ');
37616 if(this.resizeEl != this.el){
37617 width -= this.el.getFrameWidth('lr');
37618 height -= this.el.getFrameWidth('tb');
37621 var te = this.toolbar.getEl();
37622 te.setWidth(width);
37623 height -= te.getHeight();
37626 var te = this.footer.getEl();
37627 te.setWidth(width);
37628 height -= te.getHeight();
37632 if(this.adjustments){
37633 width += this.adjustments[0];
37634 height += this.adjustments[1];
37636 return {"width": width, "height": height};
37639 setSize : function(width, height){
37640 if(this.fitToFrame && !this.ignoreResize(width, height)){
37641 if(this.fitContainer && this.resizeEl != this.el){
37642 this.el.setSize(width, height);
37644 var size = this.adjustForComponents(width, height);
37645 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37646 this.fireEvent('resize', this, size.width, size.height);
37651 * Returns this panel's title
37654 getTitle : function(){
37656 if (typeof(this.title) != 'object') {
37661 for (var k in this.title) {
37662 if (!this.title.hasOwnProperty(k)) {
37666 if (k.indexOf('-') >= 0) {
37667 var s = k.split('-');
37668 for (var i = 0; i<s.length; i++) {
37669 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37672 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37679 * Set this panel's title
37680 * @param {String} title
37682 setTitle : function(title){
37683 this.title = title;
37685 this.region.updatePanelTitle(this, title);
37690 * Returns true is this panel was configured to be closable
37691 * @return {Boolean}
37693 isClosable : function(){
37694 return this.closable;
37697 beforeSlide : function(){
37699 this.resizeEl.clip();
37702 afterSlide : function(){
37704 this.resizeEl.unclip();
37708 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37709 * Will fail silently if the {@link #setUrl} method has not been called.
37710 * This does not activate the panel, just updates its content.
37712 refresh : function(){
37713 if(this.refreshDelegate){
37714 this.loaded = false;
37715 this.refreshDelegate();
37720 * Destroys this panel
37722 destroy : function(){
37723 this.el.removeAllListeners();
37724 var tempEl = document.createElement("span");
37725 tempEl.appendChild(this.el.dom);
37726 tempEl.innerHTML = "";
37732 * form - if the content panel contains a form - this is a reference to it.
37733 * @type {Roo.form.Form}
37737 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37738 * This contains a reference to it.
37744 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37754 * @param {Object} cfg Xtype definition of item to add.
37758 getChildContainer: function () {
37759 return this.getEl();
37764 var ret = new Roo.factory(cfg);
37769 if (cfg.xtype.match(/^Form$/)) {
37772 //if (this.footer) {
37773 // el = this.footer.container.insertSibling(false, 'before');
37775 el = this.el.createChild();
37778 this.form = new Roo.form.Form(cfg);
37781 if ( this.form.allItems.length) {
37782 this.form.render(el.dom);
37786 // should only have one of theses..
37787 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37788 // views.. should not be just added - used named prop 'view''
37790 cfg.el = this.el.appendChild(document.createElement("div"));
37793 var ret = new Roo.factory(cfg);
37795 ret.render && ret.render(false, ''); // render blank..
37805 * @class Roo.bootstrap.panel.Grid
37806 * @extends Roo.bootstrap.panel.Content
37808 * Create a new GridPanel.
37809 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37810 * @param {Object} config A the config object
37816 Roo.bootstrap.panel.Grid = function(config)
37820 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37821 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37823 config.el = this.wrapper;
37824 //this.el = this.wrapper;
37826 if (config.container) {
37827 // ctor'ed from a Border/panel.grid
37830 this.wrapper.setStyle("overflow", "hidden");
37831 this.wrapper.addClass('roo-grid-container');
37836 if(config.toolbar){
37837 var tool_el = this.wrapper.createChild();
37838 this.toolbar = Roo.factory(config.toolbar);
37840 if (config.toolbar.items) {
37841 ti = config.toolbar.items ;
37842 delete config.toolbar.items ;
37846 this.toolbar.render(tool_el);
37847 for(var i =0;i < ti.length;i++) {
37848 // Roo.log(['add child', items[i]]);
37849 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37851 this.toolbar.items = nitems;
37853 delete config.toolbar;
37856 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37857 config.grid.scrollBody = true;;
37858 config.grid.monitorWindowResize = false; // turn off autosizing
37859 config.grid.autoHeight = false;
37860 config.grid.autoWidth = false;
37862 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37864 if (config.background) {
37865 // render grid on panel activation (if panel background)
37866 this.on('activate', function(gp) {
37867 if (!gp.grid.rendered) {
37868 gp.grid.render(this.wrapper);
37869 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37874 this.grid.render(this.wrapper);
37875 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37878 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37879 // ??? needed ??? config.el = this.wrapper;
37884 // xtype created footer. - not sure if will work as we normally have to render first..
37885 if (this.footer && !this.footer.el && this.footer.xtype) {
37887 var ctr = this.grid.getView().getFooterPanel(true);
37888 this.footer.dataSource = this.grid.dataSource;
37889 this.footer = Roo.factory(this.footer, Roo);
37890 this.footer.render(ctr);
37900 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37901 getId : function(){
37902 return this.grid.id;
37906 * Returns the grid for this panel
37907 * @return {Roo.bootstrap.Table}
37909 getGrid : function(){
37913 setSize : function(width, height){
37914 if(!this.ignoreResize(width, height)){
37915 var grid = this.grid;
37916 var size = this.adjustForComponents(width, height);
37917 var gridel = grid.getGridEl();
37918 gridel.setSize(size.width, size.height);
37920 var thd = grid.getGridEl().select('thead',true).first();
37921 var tbd = grid.getGridEl().select('tbody', true).first();
37923 tbd.setSize(width, height - thd.getHeight());
37932 beforeSlide : function(){
37933 this.grid.getView().scroller.clip();
37936 afterSlide : function(){
37937 this.grid.getView().scroller.unclip();
37940 destroy : function(){
37941 this.grid.destroy();
37943 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37948 * @class Roo.bootstrap.panel.Nest
37949 * @extends Roo.bootstrap.panel.Content
37951 * Create a new Panel, that can contain a layout.Border.
37954 * @param {Roo.BorderLayout} layout The layout for this panel
37955 * @param {String/Object} config A string to set only the title or a config object
37957 Roo.bootstrap.panel.Nest = function(config)
37959 // construct with only one argument..
37960 /* FIXME - implement nicer consturctors
37961 if (layout.layout) {
37963 layout = config.layout;
37964 delete config.layout;
37966 if (layout.xtype && !layout.getEl) {
37967 // then layout needs constructing..
37968 layout = Roo.factory(layout, Roo);
37972 config.el = config.layout.getEl();
37974 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37976 config.layout.monitorWindowResize = false; // turn off autosizing
37977 this.layout = config.layout;
37978 this.layout.getEl().addClass("roo-layout-nested-layout");
37979 this.layout.parent = this;
37986 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37988 setSize : function(width, height){
37989 if(!this.ignoreResize(width, height)){
37990 var size = this.adjustForComponents(width, height);
37991 var el = this.layout.getEl();
37992 if (size.height < 1) {
37993 el.setWidth(size.width);
37995 el.setSize(size.width, size.height);
37997 var touch = el.dom.offsetWidth;
37998 this.layout.layout();
37999 // ie requires a double layout on the first pass
38000 if(Roo.isIE && !this.initialized){
38001 this.initialized = true;
38002 this.layout.layout();
38007 // activate all subpanels if not currently active..
38009 setActiveState : function(active){
38010 this.active = active;
38011 this.setActiveClass(active);
38014 this.fireEvent("deactivate", this);
38018 this.fireEvent("activate", this);
38019 // not sure if this should happen before or after..
38020 if (!this.layout) {
38021 return; // should not happen..
38024 for (var r in this.layout.regions) {
38025 reg = this.layout.getRegion(r);
38026 if (reg.getActivePanel()) {
38027 //reg.showPanel(reg.getActivePanel()); // force it to activate..
38028 reg.setActivePanel(reg.getActivePanel());
38031 if (!reg.panels.length) {
38034 reg.showPanel(reg.getPanel(0));
38043 * Returns the nested BorderLayout for this panel
38044 * @return {Roo.BorderLayout}
38046 getLayout : function(){
38047 return this.layout;
38051 * Adds a xtype elements to the layout of the nested panel
38055 xtype : 'ContentPanel',
38062 xtype : 'NestedLayoutPanel',
38068 items : [ ... list of content panels or nested layout panels.. ]
38072 * @param {Object} cfg Xtype definition of item to add.
38074 addxtype : function(cfg) {
38075 return this.layout.addxtype(cfg);
38080 * Ext JS Library 1.1.1
38081 * Copyright(c) 2006-2007, Ext JS, LLC.
38083 * Originally Released Under LGPL - original licence link has changed is not relivant.
38086 * <script type="text/javascript">
38089 * @class Roo.TabPanel
38090 * @extends Roo.util.Observable
38091 * A lightweight tab container.
38095 // basic tabs 1, built from existing content
38096 var tabs = new Roo.TabPanel("tabs1");
38097 tabs.addTab("script", "View Script");
38098 tabs.addTab("markup", "View Markup");
38099 tabs.activate("script");
38101 // more advanced tabs, built from javascript
38102 var jtabs = new Roo.TabPanel("jtabs");
38103 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38105 // set up the UpdateManager
38106 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38107 var updater = tab2.getUpdateManager();
38108 updater.setDefaultUrl("ajax1.htm");
38109 tab2.on('activate', updater.refresh, updater, true);
38111 // Use setUrl for Ajax loading
38112 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38113 tab3.setUrl("ajax2.htm", null, true);
38116 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38119 jtabs.activate("jtabs-1");
38122 * Create a new TabPanel.
38123 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38124 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38126 Roo.bootstrap.panel.Tabs = function(config){
38128 * The container element for this TabPanel.
38129 * @type Roo.Element
38131 this.el = Roo.get(config.el);
38134 if(typeof config == "boolean"){
38135 this.tabPosition = config ? "bottom" : "top";
38137 Roo.apply(this, config);
38141 if(this.tabPosition == "bottom"){
38142 // if tabs are at the bottom = create the body first.
38143 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38144 this.el.addClass("roo-tabs-bottom");
38146 // next create the tabs holders
38148 if (this.tabPosition == "west"){
38150 var reg = this.region; // fake it..
38152 if (!reg.mgr.parent) {
38155 reg = reg.mgr.parent.region;
38157 Roo.log("got nest?");
38159 if (reg.mgr.getRegion('west')) {
38160 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38161 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38162 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38163 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38164 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38172 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38173 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38174 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38175 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38180 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38183 // finally - if tabs are at the top, then create the body last..
38184 if(this.tabPosition != "bottom"){
38185 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38186 * @type Roo.Element
38188 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38189 this.el.addClass("roo-tabs-top");
38193 this.bodyEl.setStyle("position", "relative");
38195 this.active = null;
38196 this.activateDelegate = this.activate.createDelegate(this);
38201 * Fires when the active tab changes
38202 * @param {Roo.TabPanel} this
38203 * @param {Roo.TabPanelItem} activePanel The new active tab
38207 * @event beforetabchange
38208 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38209 * @param {Roo.TabPanel} this
38210 * @param {Object} e Set cancel to true on this object to cancel the tab change
38211 * @param {Roo.TabPanelItem} tab The tab being changed to
38213 "beforetabchange" : true
38216 Roo.EventManager.onWindowResize(this.onResize, this);
38217 this.cpad = this.el.getPadding("lr");
38218 this.hiddenCount = 0;
38221 // toolbar on the tabbar support...
38222 if (this.toolbar) {
38223 alert("no toolbar support yet");
38224 this.toolbar = false;
38226 var tcfg = this.toolbar;
38227 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38228 this.toolbar = new Roo.Toolbar(tcfg);
38229 if (Roo.isSafari) {
38230 var tbl = tcfg.container.child('table', true);
38231 tbl.setAttribute('width', '100%');
38239 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38242 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38244 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38246 tabPosition : "top",
38248 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38250 currentTabWidth : 0,
38252 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38256 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38260 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38262 preferredTabWidth : 175,
38264 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38266 resizeTabs : false,
38268 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38270 monitorResize : true,
38272 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38274 toolbar : false, // set by caller..
38276 region : false, /// set by caller
38278 disableTooltips : true, // not used yet...
38281 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38282 * @param {String} id The id of the div to use <b>or create</b>
38283 * @param {String} text The text for the tab
38284 * @param {String} content (optional) Content to put in the TabPanelItem body
38285 * @param {Boolean} closable (optional) True to create a close icon on the tab
38286 * @return {Roo.TabPanelItem} The created TabPanelItem
38288 addTab : function(id, text, content, closable, tpl)
38290 var item = new Roo.bootstrap.panel.TabItem({
38294 closable : closable,
38297 this.addTabItem(item);
38299 item.setContent(content);
38305 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38306 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38307 * @return {Roo.TabPanelItem}
38309 getTab : function(id){
38310 return this.items[id];
38314 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38315 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38317 hideTab : function(id){
38318 var t = this.items[id];
38321 this.hiddenCount++;
38322 this.autoSizeTabs();
38327 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38328 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38330 unhideTab : function(id){
38331 var t = this.items[id];
38333 t.setHidden(false);
38334 this.hiddenCount--;
38335 this.autoSizeTabs();
38340 * Adds an existing {@link Roo.TabPanelItem}.
38341 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38343 addTabItem : function(item)
38345 this.items[item.id] = item;
38346 this.items.push(item);
38347 this.autoSizeTabs();
38348 // if(this.resizeTabs){
38349 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38350 // this.autoSizeTabs();
38352 // item.autoSize();
38357 * Removes a {@link Roo.TabPanelItem}.
38358 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38360 removeTab : function(id){
38361 var items = this.items;
38362 var tab = items[id];
38363 if(!tab) { return; }
38364 var index = items.indexOf(tab);
38365 if(this.active == tab && items.length > 1){
38366 var newTab = this.getNextAvailable(index);
38371 this.stripEl.dom.removeChild(tab.pnode.dom);
38372 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38373 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38375 items.splice(index, 1);
38376 delete this.items[tab.id];
38377 tab.fireEvent("close", tab);
38378 tab.purgeListeners();
38379 this.autoSizeTabs();
38382 getNextAvailable : function(start){
38383 var items = this.items;
38385 // look for a next tab that will slide over to
38386 // replace the one being removed
38387 while(index < items.length){
38388 var item = items[++index];
38389 if(item && !item.isHidden()){
38393 // if one isn't found select the previous tab (on the left)
38396 var item = items[--index];
38397 if(item && !item.isHidden()){
38405 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38406 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38408 disableTab : function(id){
38409 var tab = this.items[id];
38410 if(tab && this.active != tab){
38416 * Enables a {@link Roo.TabPanelItem} that is disabled.
38417 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38419 enableTab : function(id){
38420 var tab = this.items[id];
38425 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38426 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38427 * @return {Roo.TabPanelItem} The TabPanelItem.
38429 activate : function(id)
38431 //Roo.log('activite:' + id);
38433 var tab = this.items[id];
38437 if(tab == this.active || tab.disabled){
38441 this.fireEvent("beforetabchange", this, e, tab);
38442 if(e.cancel !== true && !tab.disabled){
38444 this.active.hide();
38446 this.active = this.items[id];
38447 this.active.show();
38448 this.fireEvent("tabchange", this, this.active);
38454 * Gets the active {@link Roo.TabPanelItem}.
38455 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38457 getActiveTab : function(){
38458 return this.active;
38462 * Updates the tab body element to fit the height of the container element
38463 * for overflow scrolling
38464 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38466 syncHeight : function(targetHeight){
38467 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38468 var bm = this.bodyEl.getMargins();
38469 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38470 this.bodyEl.setHeight(newHeight);
38474 onResize : function(){
38475 if(this.monitorResize){
38476 this.autoSizeTabs();
38481 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38483 beginUpdate : function(){
38484 this.updating = true;
38488 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38490 endUpdate : function(){
38491 this.updating = false;
38492 this.autoSizeTabs();
38496 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38498 autoSizeTabs : function()
38500 var count = this.items.length;
38501 var vcount = count - this.hiddenCount;
38504 this.stripEl.hide();
38506 this.stripEl.show();
38509 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38514 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38515 var availWidth = Math.floor(w / vcount);
38516 var b = this.stripBody;
38517 if(b.getWidth() > w){
38518 var tabs = this.items;
38519 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38520 if(availWidth < this.minTabWidth){
38521 /*if(!this.sleft){ // incomplete scrolling code
38522 this.createScrollButtons();
38525 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38528 if(this.currentTabWidth < this.preferredTabWidth){
38529 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38535 * Returns the number of tabs in this TabPanel.
38538 getCount : function(){
38539 return this.items.length;
38543 * Resizes all the tabs to the passed width
38544 * @param {Number} The new width
38546 setTabWidth : function(width){
38547 this.currentTabWidth = width;
38548 for(var i = 0, len = this.items.length; i < len; i++) {
38549 if(!this.items[i].isHidden()) {
38550 this.items[i].setWidth(width);
38556 * Destroys this TabPanel
38557 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38559 destroy : function(removeEl){
38560 Roo.EventManager.removeResizeListener(this.onResize, this);
38561 for(var i = 0, len = this.items.length; i < len; i++){
38562 this.items[i].purgeListeners();
38564 if(removeEl === true){
38565 this.el.update("");
38570 createStrip : function(container)
38572 var strip = document.createElement("nav");
38573 strip.className = Roo.bootstrap.version == 4 ?
38574 "navbar-light bg-light" :
38575 "navbar navbar-default"; //"x-tabs-wrap";
38576 container.appendChild(strip);
38580 createStripList : function(strip)
38582 // div wrapper for retard IE
38583 // returns the "tr" element.
38584 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38585 //'<div class="x-tabs-strip-wrap">'+
38586 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38587 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38588 return strip.firstChild; //.firstChild.firstChild.firstChild;
38590 createBody : function(container)
38592 var body = document.createElement("div");
38593 Roo.id(body, "tab-body");
38594 //Roo.fly(body).addClass("x-tabs-body");
38595 Roo.fly(body).addClass("tab-content");
38596 container.appendChild(body);
38599 createItemBody :function(bodyEl, id){
38600 var body = Roo.getDom(id);
38602 body = document.createElement("div");
38605 //Roo.fly(body).addClass("x-tabs-item-body");
38606 Roo.fly(body).addClass("tab-pane");
38607 bodyEl.insertBefore(body, bodyEl.firstChild);
38611 createStripElements : function(stripEl, text, closable, tpl)
38613 var td = document.createElement("li"); // was td..
38614 td.className = 'nav-item';
38616 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38619 stripEl.appendChild(td);
38621 td.className = "x-tabs-closable";
38622 if(!this.closeTpl){
38623 this.closeTpl = new Roo.Template(
38624 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38625 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38626 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38629 var el = this.closeTpl.overwrite(td, {"text": text});
38630 var close = el.getElementsByTagName("div")[0];
38631 var inner = el.getElementsByTagName("em")[0];
38632 return {"el": el, "close": close, "inner": inner};
38635 // not sure what this is..
38636 // if(!this.tabTpl){
38637 //this.tabTpl = new Roo.Template(
38638 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38639 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38641 // this.tabTpl = new Roo.Template(
38642 // '<a href="#">' +
38643 // '<span unselectable="on"' +
38644 // (this.disableTooltips ? '' : ' title="{text}"') +
38645 // ' >{text}</span></a>'
38651 var template = tpl || this.tabTpl || false;
38654 template = new Roo.Template(
38655 Roo.bootstrap.version == 4 ?
38657 '<a class="nav-link" href="#" unselectable="on"' +
38658 (this.disableTooltips ? '' : ' title="{text}"') +
38661 '<a class="nav-link" href="#">' +
38662 '<span unselectable="on"' +
38663 (this.disableTooltips ? '' : ' title="{text}"') +
38664 ' >{text}</span></a>'
38669 switch (typeof(template)) {
38673 template = new Roo.Template(template);
38679 var el = template.overwrite(td, {"text": text});
38681 var inner = el.getElementsByTagName("span")[0];
38683 return {"el": el, "inner": inner};
38691 * @class Roo.TabPanelItem
38692 * @extends Roo.util.Observable
38693 * Represents an individual item (tab plus body) in a TabPanel.
38694 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38695 * @param {String} id The id of this TabPanelItem
38696 * @param {String} text The text for the tab of this TabPanelItem
38697 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38699 Roo.bootstrap.panel.TabItem = function(config){
38701 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38702 * @type Roo.TabPanel
38704 this.tabPanel = config.panel;
38706 * The id for this TabPanelItem
38709 this.id = config.id;
38711 this.disabled = false;
38713 this.text = config.text;
38715 this.loaded = false;
38716 this.closable = config.closable;
38719 * The body element for this TabPanelItem.
38720 * @type Roo.Element
38722 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38723 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38724 this.bodyEl.setStyle("display", "block");
38725 this.bodyEl.setStyle("zoom", "1");
38726 //this.hideAction();
38728 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38730 this.el = Roo.get(els.el);
38731 this.inner = Roo.get(els.inner, true);
38732 this.textEl = Roo.bootstrap.version == 4 ?
38733 this.el : Roo.get(this.el.dom.firstChild, true);
38735 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38736 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38739 // this.el.on("mousedown", this.onTabMouseDown, this);
38740 this.el.on("click", this.onTabClick, this);
38742 if(config.closable){
38743 var c = Roo.get(els.close, true);
38744 c.dom.title = this.closeText;
38745 c.addClassOnOver("close-over");
38746 c.on("click", this.closeClick, this);
38752 * Fires when this tab becomes the active tab.
38753 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38754 * @param {Roo.TabPanelItem} this
38758 * @event beforeclose
38759 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38760 * @param {Roo.TabPanelItem} this
38761 * @param {Object} e Set cancel to true on this object to cancel the close.
38763 "beforeclose": true,
38766 * Fires when this tab is closed.
38767 * @param {Roo.TabPanelItem} this
38771 * @event deactivate
38772 * Fires when this tab is no longer the active tab.
38773 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38774 * @param {Roo.TabPanelItem} this
38776 "deactivate" : true
38778 this.hidden = false;
38780 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38783 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38785 purgeListeners : function(){
38786 Roo.util.Observable.prototype.purgeListeners.call(this);
38787 this.el.removeAllListeners();
38790 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38793 this.status_node.addClass("active");
38796 this.tabPanel.stripWrap.repaint();
38798 this.fireEvent("activate", this.tabPanel, this);
38802 * Returns true if this tab is the active tab.
38803 * @return {Boolean}
38805 isActive : function(){
38806 return this.tabPanel.getActiveTab() == this;
38810 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38813 this.status_node.removeClass("active");
38815 this.fireEvent("deactivate", this.tabPanel, this);
38818 hideAction : function(){
38819 this.bodyEl.hide();
38820 this.bodyEl.setStyle("position", "absolute");
38821 this.bodyEl.setLeft("-20000px");
38822 this.bodyEl.setTop("-20000px");
38825 showAction : function(){
38826 this.bodyEl.setStyle("position", "relative");
38827 this.bodyEl.setTop("");
38828 this.bodyEl.setLeft("");
38829 this.bodyEl.show();
38833 * Set the tooltip for the tab.
38834 * @param {String} tooltip The tab's tooltip
38836 setTooltip : function(text){
38837 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38838 this.textEl.dom.qtip = text;
38839 this.textEl.dom.removeAttribute('title');
38841 this.textEl.dom.title = text;
38845 onTabClick : function(e){
38846 e.preventDefault();
38847 this.tabPanel.activate(this.id);
38850 onTabMouseDown : function(e){
38851 e.preventDefault();
38852 this.tabPanel.activate(this.id);
38855 getWidth : function(){
38856 return this.inner.getWidth();
38859 setWidth : function(width){
38860 var iwidth = width - this.linode.getPadding("lr");
38861 this.inner.setWidth(iwidth);
38862 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38863 this.linode.setWidth(width);
38867 * Show or hide the tab
38868 * @param {Boolean} hidden True to hide or false to show.
38870 setHidden : function(hidden){
38871 this.hidden = hidden;
38872 this.linode.setStyle("display", hidden ? "none" : "");
38876 * Returns true if this tab is "hidden"
38877 * @return {Boolean}
38879 isHidden : function(){
38880 return this.hidden;
38884 * Returns the text for this tab
38887 getText : function(){
38891 autoSize : function(){
38892 //this.el.beginMeasure();
38893 this.textEl.setWidth(1);
38895 * #2804 [new] Tabs in Roojs
38896 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38898 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38899 //this.el.endMeasure();
38903 * Sets the text for the tab (Note: this also sets the tooltip text)
38904 * @param {String} text The tab's text and tooltip
38906 setText : function(text){
38908 this.textEl.update(text);
38909 this.setTooltip(text);
38910 //if(!this.tabPanel.resizeTabs){
38911 // this.autoSize();
38915 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38917 activate : function(){
38918 this.tabPanel.activate(this.id);
38922 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38924 disable : function(){
38925 if(this.tabPanel.active != this){
38926 this.disabled = true;
38927 this.status_node.addClass("disabled");
38932 * Enables this TabPanelItem if it was previously disabled.
38934 enable : function(){
38935 this.disabled = false;
38936 this.status_node.removeClass("disabled");
38940 * Sets the content for this TabPanelItem.
38941 * @param {String} content The content
38942 * @param {Boolean} loadScripts true to look for and load scripts
38944 setContent : function(content, loadScripts){
38945 this.bodyEl.update(content, loadScripts);
38949 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38950 * @return {Roo.UpdateManager} The UpdateManager
38952 getUpdateManager : function(){
38953 return this.bodyEl.getUpdateManager();
38957 * Set a URL to be used to load the content for this TabPanelItem.
38958 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38959 * @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)
38960 * @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)
38961 * @return {Roo.UpdateManager} The UpdateManager
38963 setUrl : function(url, params, loadOnce){
38964 if(this.refreshDelegate){
38965 this.un('activate', this.refreshDelegate);
38967 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38968 this.on("activate", this.refreshDelegate);
38969 return this.bodyEl.getUpdateManager();
38973 _handleRefresh : function(url, params, loadOnce){
38974 if(!loadOnce || !this.loaded){
38975 var updater = this.bodyEl.getUpdateManager();
38976 updater.update(url, params, this._setLoaded.createDelegate(this));
38981 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38982 * Will fail silently if the setUrl method has not been called.
38983 * This does not activate the panel, just updates its content.
38985 refresh : function(){
38986 if(this.refreshDelegate){
38987 this.loaded = false;
38988 this.refreshDelegate();
38993 _setLoaded : function(){
38994 this.loaded = true;
38998 closeClick : function(e){
39001 this.fireEvent("beforeclose", this, o);
39002 if(o.cancel !== true){
39003 this.tabPanel.removeTab(this.id);
39007 * The text displayed in the tooltip for the close icon.
39010 closeText : "Close this tab"
39013 * This script refer to:
39014 * Title: International Telephone Input
39015 * Author: Jack O'Connor
39016 * Code version: v12.1.12
39017 * Availability: https://github.com/jackocnr/intl-tel-input.git
39020 Roo.bootstrap.PhoneInputData = function() {
39023 "Afghanistan (افغانستان)",
39028 "Albania (Shqipëri)",
39033 "Algeria (الجزائر)",
39058 "Antigua and Barbuda",
39068 "Armenia (Հայաստան)",
39084 "Austria (Österreich)",
39089 "Azerbaijan (Azərbaycan)",
39099 "Bahrain (البحرين)",
39104 "Bangladesh (বাংলাদেশ)",
39114 "Belarus (Беларусь)",
39119 "Belgium (België)",
39149 "Bosnia and Herzegovina (Босна и Херцеговина)",
39164 "British Indian Ocean Territory",
39169 "British Virgin Islands",
39179 "Bulgaria (България)",
39189 "Burundi (Uburundi)",
39194 "Cambodia (កម្ពុជា)",
39199 "Cameroon (Cameroun)",
39208 ["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"]
39211 "Cape Verde (Kabu Verdi)",
39216 "Caribbean Netherlands",
39227 "Central African Republic (République centrafricaine)",
39247 "Christmas Island",
39253 "Cocos (Keeling) Islands",
39264 "Comoros (جزر القمر)",
39269 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39274 "Congo (Republic) (Congo-Brazzaville)",
39294 "Croatia (Hrvatska)",
39315 "Czech Republic (Česká republika)",
39320 "Denmark (Danmark)",
39335 "Dominican Republic (República Dominicana)",
39339 ["809", "829", "849"]
39357 "Equatorial Guinea (Guinea Ecuatorial)",
39377 "Falkland Islands (Islas Malvinas)",
39382 "Faroe Islands (Føroyar)",
39403 "French Guiana (Guyane française)",
39408 "French Polynesia (Polynésie française)",
39423 "Georgia (საქართველო)",
39428 "Germany (Deutschland)",
39448 "Greenland (Kalaallit Nunaat)",
39485 "Guinea-Bissau (Guiné Bissau)",
39510 "Hungary (Magyarország)",
39515 "Iceland (Ísland)",
39535 "Iraq (العراق)",
39551 "Israel (ישראל)",
39578 "Jordan (الأردن)",
39583 "Kazakhstan (Казахстан)",
39604 "Kuwait (الكويت)",
39609 "Kyrgyzstan (Кыргызстан)",
39619 "Latvia (Latvija)",
39624 "Lebanon (لبنان)",
39639 "Libya (ليبيا)",
39649 "Lithuania (Lietuva)",
39664 "Macedonia (FYROM) (Македонија)",
39669 "Madagascar (Madagasikara)",
39699 "Marshall Islands",
39709 "Mauritania (موريتانيا)",
39714 "Mauritius (Moris)",
39735 "Moldova (Republica Moldova)",
39745 "Mongolia (Монгол)",
39750 "Montenegro (Crna Gora)",
39760 "Morocco (المغرب)",
39766 "Mozambique (Moçambique)",
39771 "Myanmar (Burma) (မြန်မာ)",
39776 "Namibia (Namibië)",
39791 "Netherlands (Nederland)",
39796 "New Caledonia (Nouvelle-Calédonie)",
39831 "North Korea (조선 민주주의 인민 공화국)",
39836 "Northern Mariana Islands",
39852 "Pakistan (پاکستان)",
39862 "Palestine (فلسطين)",
39872 "Papua New Guinea",
39914 "Réunion (La Réunion)",
39920 "Romania (România)",
39936 "Saint Barthélemy",
39947 "Saint Kitts and Nevis",
39957 "Saint Martin (Saint-Martin (partie française))",
39963 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39968 "Saint Vincent and the Grenadines",
39983 "São Tomé and Príncipe (São Tomé e Príncipe)",
39988 "Saudi Arabia (المملكة العربية السعودية)",
39993 "Senegal (Sénégal)",
40023 "Slovakia (Slovensko)",
40028 "Slovenia (Slovenija)",
40038 "Somalia (Soomaaliya)",
40048 "South Korea (대한민국)",
40053 "South Sudan (جنوب السودان)",
40063 "Sri Lanka (ශ්රී ලංකාව)",
40068 "Sudan (السودان)",
40078 "Svalbard and Jan Mayen",
40089 "Sweden (Sverige)",
40094 "Switzerland (Schweiz)",
40099 "Syria (سوريا)",
40144 "Trinidad and Tobago",
40149 "Tunisia (تونس)",
40154 "Turkey (Türkiye)",
40164 "Turks and Caicos Islands",
40174 "U.S. Virgin Islands",
40184 "Ukraine (Україна)",
40189 "United Arab Emirates (الإمارات العربية المتحدة)",
40211 "Uzbekistan (Oʻzbekiston)",
40221 "Vatican City (Città del Vaticano)",
40232 "Vietnam (Việt Nam)",
40237 "Wallis and Futuna (Wallis-et-Futuna)",
40242 "Western Sahara (الصحراء الغربية)",
40248 "Yemen (اليمن)",
40272 * This script refer to:
40273 * Title: International Telephone Input
40274 * Author: Jack O'Connor
40275 * Code version: v12.1.12
40276 * Availability: https://github.com/jackocnr/intl-tel-input.git
40280 * @class Roo.bootstrap.PhoneInput
40281 * @extends Roo.bootstrap.TriggerField
40282 * An input with International dial-code selection
40284 * @cfg {String} defaultDialCode default '+852'
40285 * @cfg {Array} preferedCountries default []
40288 * Create a new PhoneInput.
40289 * @param {Object} config Configuration options
40292 Roo.bootstrap.PhoneInput = function(config) {
40293 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40296 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40298 listWidth: undefined,
40300 selectedClass: 'active',
40302 invalidClass : "has-warning",
40304 validClass: 'has-success',
40306 allowed: '0123456789',
40311 * @cfg {String} defaultDialCode The default dial code when initializing the input
40313 defaultDialCode: '+852',
40316 * @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
40318 preferedCountries: false,
40320 getAutoCreate : function()
40322 var data = Roo.bootstrap.PhoneInputData();
40323 var align = this.labelAlign || this.parentLabelAlign();
40326 this.allCountries = [];
40327 this.dialCodeMapping = [];
40329 for (var i = 0; i < data.length; i++) {
40331 this.allCountries[i] = {
40335 priority: c[3] || 0,
40336 areaCodes: c[4] || null
40338 this.dialCodeMapping[c[2]] = {
40341 priority: c[3] || 0,
40342 areaCodes: c[4] || null
40354 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40355 maxlength: this.max_length,
40356 cls : 'form-control tel-input',
40357 autocomplete: 'new-password'
40360 var hiddenInput = {
40363 cls: 'hidden-tel-input'
40367 hiddenInput.name = this.name;
40370 if (this.disabled) {
40371 input.disabled = true;
40374 var flag_container = {
40391 cls: this.hasFeedback ? 'has-feedback' : '',
40397 cls: 'dial-code-holder',
40404 cls: 'roo-select2-container input-group',
40411 if (this.fieldLabel.length) {
40414 tooltip: 'This field is required'
40420 cls: 'control-label',
40426 html: this.fieldLabel
40429 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40435 if(this.indicatorpos == 'right') {
40436 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40443 if(align == 'left') {
40451 if(this.labelWidth > 12){
40452 label.style = "width: " + this.labelWidth + 'px';
40454 if(this.labelWidth < 13 && this.labelmd == 0){
40455 this.labelmd = this.labelWidth;
40457 if(this.labellg > 0){
40458 label.cls += ' col-lg-' + this.labellg;
40459 input.cls += ' col-lg-' + (12 - this.labellg);
40461 if(this.labelmd > 0){
40462 label.cls += ' col-md-' + this.labelmd;
40463 container.cls += ' col-md-' + (12 - this.labelmd);
40465 if(this.labelsm > 0){
40466 label.cls += ' col-sm-' + this.labelsm;
40467 container.cls += ' col-sm-' + (12 - this.labelsm);
40469 if(this.labelxs > 0){
40470 label.cls += ' col-xs-' + this.labelxs;
40471 container.cls += ' col-xs-' + (12 - this.labelxs);
40481 var settings = this;
40483 ['xs','sm','md','lg'].map(function(size){
40484 if (settings[size]) {
40485 cfg.cls += ' col-' + size + '-' + settings[size];
40489 this.store = new Roo.data.Store({
40490 proxy : new Roo.data.MemoryProxy({}),
40491 reader : new Roo.data.JsonReader({
40502 'name' : 'dialCode',
40506 'name' : 'priority',
40510 'name' : 'areaCodes',
40517 if(!this.preferedCountries) {
40518 this.preferedCountries = [
40525 var p = this.preferedCountries.reverse();
40528 for (var i = 0; i < p.length; i++) {
40529 for (var j = 0; j < this.allCountries.length; j++) {
40530 if(this.allCountries[j].iso2 == p[i]) {
40531 var t = this.allCountries[j];
40532 this.allCountries.splice(j,1);
40533 this.allCountries.unshift(t);
40539 this.store.proxy.data = {
40541 data: this.allCountries
40547 initEvents : function()
40550 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40552 this.indicator = this.indicatorEl();
40553 this.flag = this.flagEl();
40554 this.dialCodeHolder = this.dialCodeHolderEl();
40556 this.trigger = this.el.select('div.flag-box',true).first();
40557 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40562 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40563 _this.list.setWidth(lw);
40566 this.list.on('mouseover', this.onViewOver, this);
40567 this.list.on('mousemove', this.onViewMove, this);
40568 this.inputEl().on("keyup", this.onKeyUp, this);
40569 this.inputEl().on("keypress", this.onKeyPress, this);
40571 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40573 this.view = new Roo.View(this.list, this.tpl, {
40574 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40577 this.view.on('click', this.onViewClick, this);
40578 this.setValue(this.defaultDialCode);
40581 onTriggerClick : function(e)
40583 Roo.log('trigger click');
40588 if(this.isExpanded()){
40590 this.hasFocus = false;
40592 this.store.load({});
40593 this.hasFocus = true;
40598 isExpanded : function()
40600 return this.list.isVisible();
40603 collapse : function()
40605 if(!this.isExpanded()){
40609 Roo.get(document).un('mousedown', this.collapseIf, this);
40610 Roo.get(document).un('mousewheel', this.collapseIf, this);
40611 this.fireEvent('collapse', this);
40615 expand : function()
40619 if(this.isExpanded() || !this.hasFocus){
40623 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40624 this.list.setWidth(lw);
40627 this.restrictHeight();
40629 Roo.get(document).on('mousedown', this.collapseIf, this);
40630 Roo.get(document).on('mousewheel', this.collapseIf, this);
40632 this.fireEvent('expand', this);
40635 restrictHeight : function()
40637 this.list.alignTo(this.inputEl(), this.listAlign);
40638 this.list.alignTo(this.inputEl(), this.listAlign);
40641 onViewOver : function(e, t)
40643 if(this.inKeyMode){
40646 var item = this.view.findItemFromChild(t);
40649 var index = this.view.indexOf(item);
40650 this.select(index, false);
40655 onViewClick : function(view, doFocus, el, e)
40657 var index = this.view.getSelectedIndexes()[0];
40659 var r = this.store.getAt(index);
40662 this.onSelect(r, index);
40664 if(doFocus !== false && !this.blockFocus){
40665 this.inputEl().focus();
40669 onViewMove : function(e, t)
40671 this.inKeyMode = false;
40674 select : function(index, scrollIntoView)
40676 this.selectedIndex = index;
40677 this.view.select(index);
40678 if(scrollIntoView !== false){
40679 var el = this.view.getNode(index);
40681 this.list.scrollChildIntoView(el, false);
40686 createList : function()
40688 this.list = Roo.get(document.body).createChild({
40690 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40691 style: 'display:none'
40694 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40697 collapseIf : function(e)
40699 var in_combo = e.within(this.el);
40700 var in_list = e.within(this.list);
40701 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40703 if (in_combo || in_list || is_list) {
40709 onSelect : function(record, index)
40711 if(this.fireEvent('beforeselect', this, record, index) !== false){
40713 this.setFlagClass(record.data.iso2);
40714 this.setDialCode(record.data.dialCode);
40715 this.hasFocus = false;
40717 this.fireEvent('select', this, record, index);
40721 flagEl : function()
40723 var flag = this.el.select('div.flag',true).first();
40730 dialCodeHolderEl : function()
40732 var d = this.el.select('input.dial-code-holder',true).first();
40739 setDialCode : function(v)
40741 this.dialCodeHolder.dom.value = '+'+v;
40744 setFlagClass : function(n)
40746 this.flag.dom.className = 'flag '+n;
40749 getValue : function()
40751 var v = this.inputEl().getValue();
40752 if(this.dialCodeHolder) {
40753 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40758 setValue : function(v)
40760 var d = this.getDialCode(v);
40762 //invalid dial code
40763 if(v.length == 0 || !d || d.length == 0) {
40765 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40766 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40772 this.setFlagClass(this.dialCodeMapping[d].iso2);
40773 this.setDialCode(d);
40774 this.inputEl().dom.value = v.replace('+'+d,'');
40775 this.hiddenEl().dom.value = this.getValue();
40780 getDialCode : function(v)
40784 if (v.length == 0) {
40785 return this.dialCodeHolder.dom.value;
40789 if (v.charAt(0) != "+") {
40792 var numericChars = "";
40793 for (var i = 1; i < v.length; i++) {
40794 var c = v.charAt(i);
40797 if (this.dialCodeMapping[numericChars]) {
40798 dialCode = v.substr(1, i);
40800 if (numericChars.length == 4) {
40810 this.setValue(this.defaultDialCode);
40814 hiddenEl : function()
40816 return this.el.select('input.hidden-tel-input',true).first();
40819 // after setting val
40820 onKeyUp : function(e){
40821 this.setValue(this.getValue());
40824 onKeyPress : function(e){
40825 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40832 * @class Roo.bootstrap.MoneyField
40833 * @extends Roo.bootstrap.ComboBox
40834 * Bootstrap MoneyField class
40837 * Create a new MoneyField.
40838 * @param {Object} config Configuration options
40841 Roo.bootstrap.MoneyField = function(config) {
40843 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40847 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40850 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40852 allowDecimals : true,
40854 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40856 decimalSeparator : ".",
40858 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40860 decimalPrecision : 0,
40862 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40864 allowNegative : true,
40866 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40870 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40872 minValue : Number.NEGATIVE_INFINITY,
40874 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40876 maxValue : Number.MAX_VALUE,
40878 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40880 minText : "The minimum value for this field is {0}",
40882 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40884 maxText : "The maximum value for this field is {0}",
40886 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40887 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40889 nanText : "{0} is not a valid number",
40891 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40895 * @cfg {String} defaults currency of the MoneyField
40896 * value should be in lkey
40898 defaultCurrency : false,
40900 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40902 thousandsDelimiter : false,
40904 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40915 getAutoCreate : function()
40917 var align = this.labelAlign || this.parentLabelAlign();
40929 cls : 'form-control roo-money-amount-input',
40930 autocomplete: 'new-password'
40933 var hiddenInput = {
40937 cls: 'hidden-number-input'
40940 if(this.max_length) {
40941 input.maxlength = this.max_length;
40945 hiddenInput.name = this.name;
40948 if (this.disabled) {
40949 input.disabled = true;
40952 var clg = 12 - this.inputlg;
40953 var cmd = 12 - this.inputmd;
40954 var csm = 12 - this.inputsm;
40955 var cxs = 12 - this.inputxs;
40959 cls : 'row roo-money-field',
40963 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40967 cls: 'roo-select2-container input-group',
40971 cls : 'form-control roo-money-currency-input',
40972 autocomplete: 'new-password',
40974 name : this.currencyName
40978 cls : 'input-group-addon',
40992 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40996 cls: this.hasFeedback ? 'has-feedback' : '',
41007 if (this.fieldLabel.length) {
41010 tooltip: 'This field is required'
41016 cls: 'control-label',
41022 html: this.fieldLabel
41025 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41031 if(this.indicatorpos == 'right') {
41032 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41039 if(align == 'left') {
41047 if(this.labelWidth > 12){
41048 label.style = "width: " + this.labelWidth + 'px';
41050 if(this.labelWidth < 13 && this.labelmd == 0){
41051 this.labelmd = this.labelWidth;
41053 if(this.labellg > 0){
41054 label.cls += ' col-lg-' + this.labellg;
41055 input.cls += ' col-lg-' + (12 - this.labellg);
41057 if(this.labelmd > 0){
41058 label.cls += ' col-md-' + this.labelmd;
41059 container.cls += ' col-md-' + (12 - this.labelmd);
41061 if(this.labelsm > 0){
41062 label.cls += ' col-sm-' + this.labelsm;
41063 container.cls += ' col-sm-' + (12 - this.labelsm);
41065 if(this.labelxs > 0){
41066 label.cls += ' col-xs-' + this.labelxs;
41067 container.cls += ' col-xs-' + (12 - this.labelxs);
41078 var settings = this;
41080 ['xs','sm','md','lg'].map(function(size){
41081 if (settings[size]) {
41082 cfg.cls += ' col-' + size + '-' + settings[size];
41089 initEvents : function()
41091 this.indicator = this.indicatorEl();
41093 this.initCurrencyEvent();
41095 this.initNumberEvent();
41098 initCurrencyEvent : function()
41101 throw "can not find store for combo";
41104 this.store = Roo.factory(this.store, Roo.data);
41105 this.store.parent = this;
41109 this.triggerEl = this.el.select('.input-group-addon', true).first();
41111 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41116 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41117 _this.list.setWidth(lw);
41120 this.list.on('mouseover', this.onViewOver, this);
41121 this.list.on('mousemove', this.onViewMove, this);
41122 this.list.on('scroll', this.onViewScroll, this);
41125 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41128 this.view = new Roo.View(this.list, this.tpl, {
41129 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41132 this.view.on('click', this.onViewClick, this);
41134 this.store.on('beforeload', this.onBeforeLoad, this);
41135 this.store.on('load', this.onLoad, this);
41136 this.store.on('loadexception', this.onLoadException, this);
41138 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41139 "up" : function(e){
41140 this.inKeyMode = true;
41144 "down" : function(e){
41145 if(!this.isExpanded()){
41146 this.onTriggerClick();
41148 this.inKeyMode = true;
41153 "enter" : function(e){
41156 if(this.fireEvent("specialkey", this, e)){
41157 this.onViewClick(false);
41163 "esc" : function(e){
41167 "tab" : function(e){
41170 if(this.fireEvent("specialkey", this, e)){
41171 this.onViewClick(false);
41179 doRelay : function(foo, bar, hname){
41180 if(hname == 'down' || this.scope.isExpanded()){
41181 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41189 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41193 initNumberEvent : function(e)
41195 this.inputEl().on("keydown" , this.fireKey, this);
41196 this.inputEl().on("focus", this.onFocus, this);
41197 this.inputEl().on("blur", this.onBlur, this);
41199 this.inputEl().relayEvent('keyup', this);
41201 if(this.indicator){
41202 this.indicator.addClass('invisible');
41205 this.originalValue = this.getValue();
41207 if(this.validationEvent == 'keyup'){
41208 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41209 this.inputEl().on('keyup', this.filterValidation, this);
41211 else if(this.validationEvent !== false){
41212 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41215 if(this.selectOnFocus){
41216 this.on("focus", this.preFocus, this);
41219 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41220 this.inputEl().on("keypress", this.filterKeys, this);
41222 this.inputEl().relayEvent('keypress', this);
41225 var allowed = "0123456789";
41227 if(this.allowDecimals){
41228 allowed += this.decimalSeparator;
41231 if(this.allowNegative){
41235 if(this.thousandsDelimiter) {
41239 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41241 var keyPress = function(e){
41243 var k = e.getKey();
41245 var c = e.getCharCode();
41248 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41249 allowed.indexOf(String.fromCharCode(c)) === -1
41255 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41259 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41264 this.inputEl().on("keypress", keyPress, this);
41268 onTriggerClick : function(e)
41275 this.loadNext = false;
41277 if(this.isExpanded()){
41282 this.hasFocus = true;
41284 if(this.triggerAction == 'all') {
41285 this.doQuery(this.allQuery, true);
41289 this.doQuery(this.getRawValue());
41292 getCurrency : function()
41294 var v = this.currencyEl().getValue();
41299 restrictHeight : function()
41301 this.list.alignTo(this.currencyEl(), this.listAlign);
41302 this.list.alignTo(this.currencyEl(), this.listAlign);
41305 onViewClick : function(view, doFocus, el, e)
41307 var index = this.view.getSelectedIndexes()[0];
41309 var r = this.store.getAt(index);
41312 this.onSelect(r, index);
41316 onSelect : function(record, index){
41318 if(this.fireEvent('beforeselect', this, record, index) !== false){
41320 this.setFromCurrencyData(index > -1 ? record.data : false);
41324 this.fireEvent('select', this, record, index);
41328 setFromCurrencyData : function(o)
41332 this.lastCurrency = o;
41334 if (this.currencyField) {
41335 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41337 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41340 this.lastSelectionText = currency;
41342 //setting default currency
41343 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41344 this.setCurrency(this.defaultCurrency);
41348 this.setCurrency(currency);
41351 setFromData : function(o)
41355 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41357 this.setFromCurrencyData(c);
41362 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41364 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41367 this.setValue(value);
41371 setCurrency : function(v)
41373 this.currencyValue = v;
41376 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41381 setValue : function(v)
41383 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41389 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41391 this.inputEl().dom.value = (v == '') ? '' :
41392 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41394 if(!this.allowZero && v === '0') {
41395 this.hiddenEl().dom.value = '';
41396 this.inputEl().dom.value = '';
41403 getRawValue : function()
41405 var v = this.inputEl().getValue();
41410 getValue : function()
41412 return this.fixPrecision(this.parseValue(this.getRawValue()));
41415 parseValue : function(value)
41417 if(this.thousandsDelimiter) {
41419 r = new RegExp(",", "g");
41420 value = value.replace(r, "");
41423 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41424 return isNaN(value) ? '' : value;
41428 fixPrecision : function(value)
41430 if(this.thousandsDelimiter) {
41432 r = new RegExp(",", "g");
41433 value = value.replace(r, "");
41436 var nan = isNaN(value);
41438 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41439 return nan ? '' : value;
41441 return parseFloat(value).toFixed(this.decimalPrecision);
41444 decimalPrecisionFcn : function(v)
41446 return Math.floor(v);
41449 validateValue : function(value)
41451 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41455 var num = this.parseValue(value);
41458 this.markInvalid(String.format(this.nanText, value));
41462 if(num < this.minValue){
41463 this.markInvalid(String.format(this.minText, this.minValue));
41467 if(num > this.maxValue){
41468 this.markInvalid(String.format(this.maxText, this.maxValue));
41475 validate : function()
41477 if(this.disabled || this.allowBlank){
41482 var currency = this.getCurrency();
41484 if(this.validateValue(this.getRawValue()) && currency.length){
41489 this.markInvalid();
41493 getName: function()
41498 beforeBlur : function()
41504 var v = this.parseValue(this.getRawValue());
41511 onBlur : function()
41515 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41516 //this.el.removeClass(this.focusClass);
41519 this.hasFocus = false;
41521 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41525 var v = this.getValue();
41527 if(String(v) !== String(this.startValue)){
41528 this.fireEvent('change', this, v, this.startValue);
41531 this.fireEvent("blur", this);
41534 inputEl : function()
41536 return this.el.select('.roo-money-amount-input', true).first();
41539 currencyEl : function()
41541 return this.el.select('.roo-money-currency-input', true).first();
41544 hiddenEl : function()
41546 return this.el.select('input.hidden-number-input',true).first();
41550 * @class Roo.bootstrap.BezierSignature
41551 * @extends Roo.bootstrap.Component
41552 * Bootstrap BezierSignature class
41553 * This script refer to:
41554 * Title: Signature Pad
41556 * Availability: https://github.com/szimek/signature_pad
41559 * Create a new BezierSignature
41560 * @param {Object} config The config object
41563 Roo.bootstrap.BezierSignature = function(config){
41564 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41570 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
41577 mouse_btn_down: true,
41580 * @cfg {int} canvas height
41582 canvas_height: '200px',
41585 * @cfg {float|function} Radius of a single dot.
41590 * @cfg {float} Minimum width of a line. Defaults to 0.5.
41595 * @cfg {float} Maximum width of a line. Defaults to 2.5.
41600 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41605 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41610 * @cfg {string} Color used to clear the background. Can be any color format accepted by context.fillStyle. Defaults to "rgba(0,0,0,0)" (transparent black). Use a non-transparent color e.g. "rgb(255,255,255)" (opaque white) if you'd like to save signatures as JPEG images.
41612 bg_color: 'rgba(0, 0, 0, 0)',
41615 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41617 dot_color: 'black',
41620 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41622 velocity_filter_weight: 0.7,
41625 * @cfg {function} Callback when stroke begin.
41630 * @cfg {function} Callback when stroke end.
41634 getAutoCreate : function()
41636 var cls = 'roo-signature column';
41639 cls += ' ' + this.cls;
41649 for(var i = 0; i < col_sizes.length; i++) {
41650 if(this[col_sizes[i]]) {
41651 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41661 cls: 'roo-signature-body',
41665 cls: 'roo-signature-body-canvas',
41666 height: this.canvas_height,
41667 width: this.canvas_width
41674 style: 'display: none'
41682 initEvents: function()
41684 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41686 var canvas = this.canvasEl();
41688 // mouse && touch event swapping...
41689 canvas.dom.style.touchAction = 'none';
41690 canvas.dom.style.msTouchAction = 'none';
41692 this.mouse_btn_down = false;
41693 canvas.on('mousedown', this._handleMouseDown, this);
41694 canvas.on('mousemove', this._handleMouseMove, this);
41695 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41697 if (window.PointerEvent) {
41698 canvas.on('pointerdown', this._handleMouseDown, this);
41699 canvas.on('pointermove', this._handleMouseMove, this);
41700 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41703 if ('ontouchstart' in window) {
41704 canvas.on('touchstart', this._handleTouchStart, this);
41705 canvas.on('touchmove', this._handleTouchMove, this);
41706 canvas.on('touchend', this._handleTouchEnd, this);
41709 Roo.EventManager.onWindowResize(this.resize, this, true);
41711 // file input event
41712 this.fileEl().on('change', this.uploadImage, this);
41719 resize: function(){
41721 var canvas = this.canvasEl().dom;
41722 var ctx = this.canvasElCtx();
41723 var img_data = false;
41725 if(canvas.width > 0) {
41726 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41728 // setting canvas width will clean img data
41731 var style = window.getComputedStyle ?
41732 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41734 var padding_left = parseInt(style.paddingLeft) || 0;
41735 var padding_right = parseInt(style.paddingRight) || 0;
41737 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41740 ctx.putImageData(img_data, 0, 0);
41744 _handleMouseDown: function(e)
41746 if (e.browserEvent.which === 1) {
41747 this.mouse_btn_down = true;
41748 this.strokeBegin(e);
41752 _handleMouseMove: function (e)
41754 if (this.mouse_btn_down) {
41755 this.strokeMoveUpdate(e);
41759 _handleMouseUp: function (e)
41761 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41762 this.mouse_btn_down = false;
41767 _handleTouchStart: function (e) {
41769 e.preventDefault();
41770 if (e.browserEvent.targetTouches.length === 1) {
41771 // var touch = e.browserEvent.changedTouches[0];
41772 // this.strokeBegin(touch);
41774 this.strokeBegin(e); // assume e catching the correct xy...
41778 _handleTouchMove: function (e) {
41779 e.preventDefault();
41780 // var touch = event.targetTouches[0];
41781 // _this._strokeMoveUpdate(touch);
41782 this.strokeMoveUpdate(e);
41785 _handleTouchEnd: function (e) {
41786 var wasCanvasTouched = e.target === this.canvasEl().dom;
41787 if (wasCanvasTouched) {
41788 e.preventDefault();
41789 // var touch = event.changedTouches[0];
41790 // _this._strokeEnd(touch);
41795 reset: function () {
41796 this._lastPoints = [];
41797 this._lastVelocity = 0;
41798 this._lastWidth = (this.min_width + this.max_width) / 2;
41799 this.canvasElCtx().fillStyle = this.dot_color;
41802 strokeMoveUpdate: function(e)
41804 this.strokeUpdate(e);
41806 if (this.throttle) {
41807 this.throttleStroke(this.strokeUpdate, this.throttle);
41810 this.strokeUpdate(e);
41814 strokeBegin: function(e)
41816 var newPointGroup = {
41817 color: this.dot_color,
41821 if (typeof this.onBegin === 'function') {
41825 this.curve_data.push(newPointGroup);
41827 this.strokeUpdate(e);
41830 strokeUpdate: function(e)
41832 var rect = this.canvasEl().dom.getBoundingClientRect();
41833 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41834 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41835 var lastPoints = lastPointGroup.points;
41836 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41837 var isLastPointTooClose = lastPoint
41838 ? point.distanceTo(lastPoint) <= this.min_distance
41840 var color = lastPointGroup.color;
41841 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41842 var curve = this.addPoint(point);
41844 this.drawDot({color: color, point: point});
41847 this.drawCurve({color: color, curve: curve});
41857 strokeEnd: function(e)
41859 this.strokeUpdate(e);
41860 if (typeof this.onEnd === 'function') {
41865 addPoint: function (point) {
41866 var _lastPoints = this._lastPoints;
41867 _lastPoints.push(point);
41868 if (_lastPoints.length > 2) {
41869 if (_lastPoints.length === 3) {
41870 _lastPoints.unshift(_lastPoints[0]);
41872 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41873 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41874 _lastPoints.shift();
41880 calculateCurveWidths: function (startPoint, endPoint) {
41881 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41882 (1 - this.velocity_filter_weight) * this._lastVelocity;
41884 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41887 start: this._lastWidth
41890 this._lastVelocity = velocity;
41891 this._lastWidth = newWidth;
41895 drawDot: function (_a) {
41896 var color = _a.color, point = _a.point;
41897 var ctx = this.canvasElCtx();
41898 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41900 this.drawCurveSegment(point.x, point.y, width);
41902 ctx.fillStyle = color;
41906 drawCurve: function (_a) {
41907 var color = _a.color, curve = _a.curve;
41908 var ctx = this.canvasElCtx();
41909 var widthDelta = curve.endWidth - curve.startWidth;
41910 var drawSteps = Math.floor(curve.length()) * 2;
41912 ctx.fillStyle = color;
41913 for (var i = 0; i < drawSteps; i += 1) {
41914 var t = i / drawSteps;
41920 var x = uuu * curve.startPoint.x;
41921 x += 3 * uu * t * curve.control1.x;
41922 x += 3 * u * tt * curve.control2.x;
41923 x += ttt * curve.endPoint.x;
41924 var y = uuu * curve.startPoint.y;
41925 y += 3 * uu * t * curve.control1.y;
41926 y += 3 * u * tt * curve.control2.y;
41927 y += ttt * curve.endPoint.y;
41928 var width = curve.startWidth + ttt * widthDelta;
41929 this.drawCurveSegment(x, y, width);
41935 drawCurveSegment: function (x, y, width) {
41936 var ctx = this.canvasElCtx();
41938 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
41939 this.is_empty = false;
41944 var ctx = this.canvasElCtx();
41945 var canvas = this.canvasEl().dom;
41946 ctx.fillStyle = this.bg_color;
41947 ctx.clearRect(0, 0, canvas.width, canvas.height);
41948 ctx.fillRect(0, 0, canvas.width, canvas.height);
41949 this.curve_data = [];
41951 this.is_empty = true;
41956 return this.el.select('input',true).first();
41959 canvasEl: function()
41961 return this.el.select('canvas',true).first();
41964 canvasElCtx: function()
41966 return this.el.select('canvas',true).first().dom.getContext('2d');
41969 getImage: function(type)
41971 if(this.is_empty) {
41976 return this.canvasEl().dom.toDataURL('image/'+type, 1);
41979 drawFromImage: function(img_src)
41981 var img = new Image();
41983 img.onload = function(){
41984 this.canvasElCtx().drawImage(img, 0, 0);
41989 this.is_empty = false;
41992 selectImage: function()
41994 this.fileEl().dom.click();
41997 uploadImage: function(e)
41999 var reader = new FileReader();
42001 reader.onload = function(e){
42002 var img = new Image();
42003 img.onload = function(){
42005 this.canvasElCtx().drawImage(img, 0, 0);
42007 img.src = e.target.result;
42010 reader.readAsDataURL(e.target.files[0]);
42013 // Bezier Point Constructor
42014 Point: (function () {
42015 function Point(x, y, time) {
42018 this.time = time || Date.now();
42020 Point.prototype.distanceTo = function (start) {
42021 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
42023 Point.prototype.equals = function (other) {
42024 return this.x === other.x && this.y === other.y && this.time === other.time;
42026 Point.prototype.velocityFrom = function (start) {
42027 return this.time !== start.time
42028 ? this.distanceTo(start) / (this.time - start.time)
42035 // Bezier Constructor
42036 Bezier: (function () {
42037 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
42038 this.startPoint = startPoint;
42039 this.control2 = control2;
42040 this.control1 = control1;
42041 this.endPoint = endPoint;
42042 this.startWidth = startWidth;
42043 this.endWidth = endWidth;
42045 Bezier.fromPoints = function (points, widths, scope) {
42046 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
42047 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
42048 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42050 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42051 var dx1 = s1.x - s2.x;
42052 var dy1 = s1.y - s2.y;
42053 var dx2 = s2.x - s3.x;
42054 var dy2 = s2.y - s3.y;
42055 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42056 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42057 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42058 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42059 var dxm = m1.x - m2.x;
42060 var dym = m1.y - m2.y;
42061 var k = l2 / (l1 + l2);
42062 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42063 var tx = s2.x - cm.x;
42064 var ty = s2.y - cm.y;
42066 c1: new scope.Point(m1.x + tx, m1.y + ty),
42067 c2: new scope.Point(m2.x + tx, m2.y + ty)
42070 Bezier.prototype.length = function () {
42075 for (var i = 0; i <= steps; i += 1) {
42077 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42078 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42080 var xdiff = cx - px;
42081 var ydiff = cy - py;
42082 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42089 Bezier.prototype.point = function (t, start, c1, c2, end) {
42090 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42091 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42092 + (3.0 * c2 * (1.0 - t) * t * t)
42093 + (end * t * t * t);
42098 throttleStroke: function(fn, wait) {
42099 if (wait === void 0) { wait = 250; }
42101 var timeout = null;
42105 var later = function () {
42106 previous = Date.now();
42108 result = fn.apply(storedContext, storedArgs);
42110 storedContext = null;
42114 return function wrapper() {
42116 for (var _i = 0; _i < arguments.length; _i++) {
42117 args[_i] = arguments[_i];
42119 var now = Date.now();
42120 var remaining = wait - (now - previous);
42121 storedContext = this;
42123 if (remaining <= 0 || remaining > wait) {
42125 clearTimeout(timeout);
42129 result = fn.apply(storedContext, storedArgs);
42131 storedContext = null;
42135 else if (!timeout) {
42136 timeout = window.setTimeout(later, remaining);