2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets[0], function(s) {
10 if (s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 addxtype : function(tree,cntr)
179 cn = Roo.factory(tree);
180 //Roo.log(['addxtype', cn]);
182 cn.parentType = this.xtype; //??
183 cn.parentId = this.id;
185 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 if (typeof(cn.container_method) == 'string') {
187 cntr = cn.container_method;
191 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
193 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
195 var build_from_html = Roo.XComponent.build_from_html;
197 var is_body = (tree.xtype == 'Body') ;
199 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
201 var self_cntr_el = Roo.get(this[cntr](false));
203 // do not try and build conditional elements
204 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
208 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
209 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
210 return this.addxtypeChild(tree,cntr, is_body);
213 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
216 return this.addxtypeChild(Roo.apply({}, tree),cntr);
219 Roo.log('skipping render');
225 if (!build_from_html) {
229 // this i think handles overlaying multiple children of the same type
230 // with the sam eelement.. - which might be buggy..
232 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
238 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
242 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
249 addxtypeChild : function (tree, cntr, is_body)
251 Roo.debug && Roo.log('addxtypeChild:' + cntr);
253 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
256 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
257 (typeof(tree['flexy:foreach']) != 'undefined');
261 skip_children = false;
262 // render the element if it's not BODY.
265 // if parent was disabled, then do not try and create the children..
266 if(!this[cntr](true)){
271 cn = Roo.factory(tree);
273 cn.parentType = this.xtype; //??
274 cn.parentId = this.id;
276 var build_from_html = Roo.XComponent.build_from_html;
279 // does the container contain child eleemnts with 'xtype' attributes.
280 // that match this xtype..
281 // note - when we render we create these as well..
282 // so we should check to see if body has xtype set.
283 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
285 var self_cntr_el = Roo.get(this[cntr](false));
286 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
288 //Roo.log(Roo.XComponent.build_from_html);
289 //Roo.log("got echild:");
292 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
293 // and are not displayed -this causes this to use up the wrong element when matching.
294 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
297 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
298 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
304 //echild.dom.removeAttribute('xtype');
306 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
307 Roo.debug && Roo.log(self_cntr_el);
308 Roo.debug && Roo.log(echild);
309 Roo.debug && Roo.log(cn);
315 // if object has flexy:if - then it may or may not be rendered.
316 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
317 // skip a flexy if element.
318 Roo.debug && Roo.log('skipping render');
319 Roo.debug && Roo.log(tree);
321 Roo.debug && Roo.log('skipping all children');
322 skip_children = true;
327 // actually if flexy:foreach is found, we really want to create
328 // multiple copies here...
330 //Roo.log(this[cntr]());
331 // some elements do not have render methods.. like the layouts...
333 if(this[cntr](true) === false){
338 cn.render && cn.render(this[cntr](true));
341 // then add the element..
348 if (typeof (tree.menu) != 'undefined') {
349 tree.menu.parentType = cn.xtype;
350 tree.menu.triggerEl = cn.el;
351 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
355 if (!tree.items || !tree.items.length) {
357 //Roo.log(["no children", this]);
362 var items = tree.items;
365 //Roo.log(items.length);
367 if (!skip_children) {
368 for(var i =0;i < items.length;i++) {
369 // Roo.log(['add child', items[i]]);
370 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
376 //Roo.log("fire childrenrendered");
378 cn.fireEvent('childrenrendered', this);
384 * Set the element that will be used to show or hide
386 setVisibilityEl : function(el)
388 this.visibilityEl = el;
392 * Get the element that will be used to show or hide
394 getVisibilityEl : function()
396 if (typeof(this.visibilityEl) == 'object') {
397 return this.visibilityEl;
400 if (typeof(this.visibilityEl) == 'string') {
401 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
408 * Show a component - removes 'hidden' class
412 if(!this.getVisibilityEl()){
416 this.getVisibilityEl().removeClass(['hidden','d-none']);
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass(['hidden','d-none']);
433 this.fireEvent('hide', this);
446 * @class Roo.bootstrap.Body
447 * @extends Roo.bootstrap.Component
448 * Bootstrap Body class
452 * @param {Object} config The config object
455 Roo.bootstrap.Body = function(config){
457 config = config || {};
459 Roo.bootstrap.Body.superclass.constructor.call(this, config);
460 this.el = Roo.get(config.el ? config.el : document.body );
461 if (this.cls && this.cls.length) {
462 Roo.get(document.body).addClass(this.cls);
466 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
468 is_body : true,// just to make sure it's constructed?
473 onRender : function(ct, position)
475 /* Roo.log("Roo.bootstrap.Body - onRender");
476 if (this.cls && this.cls.length) {
477 Roo.get(document.body).addClass(this.cls);
496 * @class Roo.bootstrap.ButtonGroup
497 * @extends Roo.bootstrap.Component
498 * Bootstrap ButtonGroup class
499 * @cfg {String} size lg | sm | xs (default empty normal)
500 * @cfg {String} align vertical | justified (default none)
501 * @cfg {String} direction up | down (default down)
502 * @cfg {Boolean} toolbar false | true
503 * @cfg {Boolean} btn true | false
508 * @param {Object} config The config object
511 Roo.bootstrap.ButtonGroup = function(config){
512 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
515 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
523 getAutoCreate : function(){
529 cfg.html = this.html || cfg.html;
540 if (['vertical','justified'].indexOf(this.align)!==-1) {
541 cfg.cls = 'btn-group-' + this.align;
543 if (this.align == 'justified') {
544 console.log(this.items);
548 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
549 cfg.cls += ' btn-group-' + this.size;
552 if (this.direction == 'up') {
553 cfg.cls += ' dropup' ;
559 * Add a button to the group (similar to NavItem API.)
561 addItem : function(cfg)
563 var cn = new Roo.bootstrap.Button(cfg);
565 cn.parentId = this.id;
566 cn.onRender(this.el, null);
580 * @class Roo.bootstrap.Button
581 * @extends Roo.bootstrap.Component
582 * Bootstrap Button class
583 * @cfg {String} html The button content
584 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
585 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
586 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
587 * @cfg {String} size ( lg | sm | xs)
588 * @cfg {String} tag ( a | input | submit)
589 * @cfg {String} href empty or href
590 * @cfg {Boolean} disabled default false;
591 * @cfg {Boolean} isClose default false;
592 * @cfg {String} glyphicon depricated - use fa
593 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
594 * @cfg {String} badge text for badge
595 * @cfg {String} theme (default|glow)
596 * @cfg {Boolean} inverse dark themed version
597 * @cfg {Boolean} toggle is it a slidy toggle button
598 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
599 * @cfg {String} ontext text for on slidy toggle state
600 * @cfg {String} offtext text for off slidy toggle state
601 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
602 * @cfg {Boolean} removeClass remove the standard class..
603 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
606 * Create a new button
607 * @param {Object} config The config object
611 Roo.bootstrap.Button = function(config){
612 Roo.bootstrap.Button.superclass.constructor.call(this, config);
613 this.weightClass = ["btn-default btn-outline-secondary",
625 * When a butotn is pressed
626 * @param {Roo.bootstrap.Button} btn
627 * @param {Roo.EventObject} e
632 * After the button has been toggles
633 * @param {Roo.bootstrap.Button} btn
634 * @param {Roo.EventObject} e
635 * @param {boolean} pressed (also available as button.pressed)
641 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
662 preventDefault: true,
670 getAutoCreate : function(){
678 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
679 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
684 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
686 if (this.toggle == true) {
689 cls: 'slider-frame roo-button',
694 'data-off-text':'OFF',
695 cls: 'slider-button',
701 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
702 cfg.cls += ' '+this.weight;
711 cfg["aria-hidden"] = true;
713 cfg.html = "×";
719 if (this.theme==='default') {
720 cfg.cls = 'btn roo-button';
722 //if (this.parentType != 'Navbar') {
723 this.weight = this.weight.length ? this.weight : 'default';
725 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
727 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
728 var weight = this.weight == 'default' ? 'secondary' : this.weight;
729 cfg.cls += ' btn-' + outline + weight;
730 if (this.weight == 'default') {
732 cfg.cls += ' btn-' + this.weight;
735 } else if (this.theme==='glow') {
738 cfg.cls = 'btn-glow roo-button';
740 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
742 cfg.cls += ' ' + this.weight;
748 this.cls += ' inverse';
752 if (this.active || this.pressed === true) {
753 cfg.cls += ' active';
757 cfg.disabled = 'disabled';
761 Roo.log('changing to ul' );
763 this.glyphicon = 'caret';
764 if (Roo.bootstrap.version == 4) {
765 this.fa = 'caret-down';
770 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
772 //gsRoo.log(this.parentType);
773 if (this.parentType === 'Navbar' && !this.parent().bar) {
774 Roo.log('changing to li?');
783 href : this.href || '#'
786 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
787 cfg.cls += ' dropdown';
794 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
796 if (this.glyphicon) {
797 cfg.html = ' ' + cfg.html;
802 cls: 'glyphicon glyphicon-' + this.glyphicon
807 cfg.html = ' ' + cfg.html;
812 cls: 'fa fas fa-' + this.fa
822 // cfg.cls='btn roo-button';
826 var value = cfg.html;
831 cls: 'glyphicon glyphicon-' + this.glyphicon,
838 cls: 'fa fas fa-' + this.fa,
843 var bw = this.badge_weight.length ? this.badge_weight :
844 (this.weight.length ? this.weight : 'secondary');
845 bw = bw == 'default' ? 'secondary' : bw;
851 cls: 'badge badge-' + bw,
860 cfg.cls += ' dropdown';
861 cfg.html = typeof(cfg.html) != 'undefined' ?
862 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
865 if (cfg.tag !== 'a' && this.href !== '') {
866 throw "Tag must be a to set href.";
867 } else if (this.href.length > 0) {
868 cfg.href = this.href;
871 if(this.removeClass){
876 cfg.target = this.target;
881 initEvents: function() {
882 // Roo.log('init events?');
883 // Roo.log(this.el.dom);
886 if (typeof (this.menu) != 'undefined') {
887 this.menu.parentType = this.xtype;
888 this.menu.triggerEl = this.el;
889 this.addxtype(Roo.apply({}, this.menu));
893 if (this.el.hasClass('roo-button')) {
894 this.el.on('click', this.onClick, this);
896 this.el.select('.roo-button').on('click', this.onClick, this);
899 if(this.removeClass){
900 this.el.on('click', this.onClick, this);
903 this.el.enableDisplayMode();
906 onClick : function(e)
912 Roo.log('button on click ');
913 if(this.preventDefault){
917 if (this.pressed === true || this.pressed === false) {
918 this.toggleActive(e);
922 this.fireEvent('click', this, e);
926 * Enables this button
930 this.disabled = false;
931 this.el.removeClass('disabled');
935 * Disable this button
939 this.disabled = true;
940 this.el.addClass('disabled');
943 * sets the active state on/off,
944 * @param {Boolean} state (optional) Force a particular state
946 setActive : function(v) {
948 this.el[v ? 'addClass' : 'removeClass']('active');
952 * toggles the current active state
954 toggleActive : function(e)
956 this.setActive(!this.pressed);
957 this.fireEvent('toggle', this, e, !this.pressed);
960 * get the current active state
961 * @return {boolean} true if it's active
963 isActive : function()
965 return this.el.hasClass('active');
968 * set the text of the first selected button
970 setText : function(str)
972 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
975 * get the text of the first selected button
979 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
982 setWeight : function(str)
984 this.el.removeClass(this.weightClass);
986 var outline = this.outline ? 'outline-' : '';
987 if (str == 'default') {
988 this.el.addClass('btn-default btn-outline-secondary');
991 this.el.addClass('btn-' + outline + str);
1005 * @class Roo.bootstrap.Column
1006 * @extends Roo.bootstrap.Component
1007 * Bootstrap Column class
1008 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1009 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1010 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1011 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1012 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1013 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1014 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1015 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1018 * @cfg {Boolean} hidden (true|false) hide the element
1019 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1020 * @cfg {String} fa (ban|check|...) font awesome icon
1021 * @cfg {Number} fasize (1|2|....) font awsome size
1023 * @cfg {String} icon (info-sign|check|...) glyphicon name
1025 * @cfg {String} html content of column.
1028 * Create a new Column
1029 * @param {Object} config The config object
1032 Roo.bootstrap.Column = function(config){
1033 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1036 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1054 getAutoCreate : function(){
1055 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1063 ['xs','sm','md','lg'].map(function(size){
1064 //Roo.log( size + ':' + settings[size]);
1066 if (settings[size+'off'] !== false) {
1067 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1070 if (settings[size] === false) {
1074 if (!settings[size]) { // 0 = hidden
1075 cfg.cls += ' hidden-' + size;
1078 cfg.cls += ' col-' + size + '-' + settings[size];
1083 cfg.cls += ' hidden';
1086 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1087 cfg.cls +=' alert alert-' + this.alert;
1091 if (this.html.length) {
1092 cfg.html = this.html;
1096 if (this.fasize > 1) {
1097 fasize = ' fa-' + this.fasize + 'x';
1099 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1104 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1123 * @class Roo.bootstrap.Container
1124 * @extends Roo.bootstrap.Component
1125 * Bootstrap Container class
1126 * @cfg {Boolean} jumbotron is it a jumbotron element
1127 * @cfg {String} html content of element
1128 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1129 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1130 * @cfg {String} header content of header (for panel)
1131 * @cfg {String} footer content of footer (for panel)
1132 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1133 * @cfg {String} tag (header|aside|section) type of HTML tag.
1134 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1135 * @cfg {String} fa font awesome icon
1136 * @cfg {String} icon (info-sign|check|...) glyphicon name
1137 * @cfg {Boolean} hidden (true|false) hide the element
1138 * @cfg {Boolean} expandable (true|false) default false
1139 * @cfg {Boolean} expanded (true|false) default true
1140 * @cfg {String} rheader contet on the right of header
1141 * @cfg {Boolean} clickable (true|false) default false
1145 * Create a new Container
1146 * @param {Object} config The config object
1149 Roo.bootstrap.Container = function(config){
1150 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1156 * After the panel has been expand
1158 * @param {Roo.bootstrap.Container} this
1163 * After the panel has been collapsed
1165 * @param {Roo.bootstrap.Container} this
1170 * When a element is chick
1171 * @param {Roo.bootstrap.Container} this
1172 * @param {Roo.EventObject} e
1178 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1196 getChildContainer : function() {
1202 if (this.panel.length) {
1203 return this.el.select('.panel-body',true).first();
1210 getAutoCreate : function(){
1213 tag : this.tag || 'div',
1217 if (this.jumbotron) {
1218 cfg.cls = 'jumbotron';
1223 // - this is applied by the parent..
1225 // cfg.cls = this.cls + '';
1228 if (this.sticky.length) {
1230 var bd = Roo.get(document.body);
1231 if (!bd.hasClass('bootstrap-sticky')) {
1232 bd.addClass('bootstrap-sticky');
1233 Roo.select('html',true).setStyle('height', '100%');
1236 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1240 if (this.well.length) {
1241 switch (this.well) {
1244 cfg.cls +=' well well-' +this.well;
1253 cfg.cls += ' hidden';
1257 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1258 cfg.cls +=' alert alert-' + this.alert;
1263 if (this.panel.length) {
1264 cfg.cls += ' panel panel-' + this.panel;
1266 if (this.header.length) {
1270 if(this.expandable){
1272 cfg.cls = cfg.cls + ' expandable';
1276 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1284 cls : 'panel-title',
1285 html : (this.expandable ? ' ' : '') + this.header
1289 cls: 'panel-header-right',
1295 cls : 'panel-heading',
1296 style : this.expandable ? 'cursor: pointer' : '',
1304 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1309 if (this.footer.length) {
1311 cls : 'panel-footer',
1320 body.html = this.html || cfg.html;
1321 // prefix with the icons..
1323 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1326 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1331 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1332 cfg.cls = 'container';
1338 initEvents: function()
1340 if(this.expandable){
1341 var headerEl = this.headerEl();
1344 headerEl.on('click', this.onToggleClick, this);
1349 this.el.on('click', this.onClick, this);
1354 onToggleClick : function()
1356 var headerEl = this.headerEl();
1372 if(this.fireEvent('expand', this)) {
1374 this.expanded = true;
1376 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1378 this.el.select('.panel-body',true).first().removeClass('hide');
1380 var toggleEl = this.toggleEl();
1386 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1391 collapse : function()
1393 if(this.fireEvent('collapse', this)) {
1395 this.expanded = false;
1397 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1398 this.el.select('.panel-body',true).first().addClass('hide');
1400 var toggleEl = this.toggleEl();
1406 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1410 toggleEl : function()
1412 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1416 return this.el.select('.panel-heading .fa',true).first();
1419 headerEl : function()
1421 if(!this.el || !this.panel.length || !this.header.length){
1425 return this.el.select('.panel-heading',true).first()
1430 if(!this.el || !this.panel.length){
1434 return this.el.select('.panel-body',true).first()
1437 titleEl : function()
1439 if(!this.el || !this.panel.length || !this.header.length){
1443 return this.el.select('.panel-title',true).first();
1446 setTitle : function(v)
1448 var titleEl = this.titleEl();
1454 titleEl.dom.innerHTML = v;
1457 getTitle : function()
1460 var titleEl = this.titleEl();
1466 return titleEl.dom.innerHTML;
1469 setRightTitle : function(v)
1471 var t = this.el.select('.panel-header-right',true).first();
1477 t.dom.innerHTML = v;
1480 onClick : function(e)
1484 this.fireEvent('click', this, e);
1497 * @class Roo.bootstrap.Img
1498 * @extends Roo.bootstrap.Component
1499 * Bootstrap Img class
1500 * @cfg {Boolean} imgResponsive false | true
1501 * @cfg {String} border rounded | circle | thumbnail
1502 * @cfg {String} src image source
1503 * @cfg {String} alt image alternative text
1504 * @cfg {String} href a tag href
1505 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1506 * @cfg {String} xsUrl xs image source
1507 * @cfg {String} smUrl sm image source
1508 * @cfg {String} mdUrl md image source
1509 * @cfg {String} lgUrl lg image source
1512 * Create a new Input
1513 * @param {Object} config The config object
1516 Roo.bootstrap.Img = function(config){
1517 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1523 * The img click event for the img.
1524 * @param {Roo.EventObject} e
1530 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1532 imgResponsive: true,
1542 getAutoCreate : function()
1544 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1545 return this.createSingleImg();
1550 cls: 'roo-image-responsive-group',
1555 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1557 if(!_this[size + 'Url']){
1563 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1564 html: _this.html || cfg.html,
1565 src: _this[size + 'Url']
1568 img.cls += ' roo-image-responsive-' + size;
1570 var s = ['xs', 'sm', 'md', 'lg'];
1572 s.splice(s.indexOf(size), 1);
1574 Roo.each(s, function(ss){
1575 img.cls += ' hidden-' + ss;
1578 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1579 cfg.cls += ' img-' + _this.border;
1583 cfg.alt = _this.alt;
1596 a.target = _this.target;
1600 cfg.cn.push((_this.href) ? a : img);
1607 createSingleImg : function()
1611 cls: (this.imgResponsive) ? 'img-responsive' : '',
1613 src : 'about:blank' // just incase src get's set to undefined?!?
1616 cfg.html = this.html || cfg.html;
1618 cfg.src = this.src || cfg.src;
1620 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1621 cfg.cls += ' img-' + this.border;
1638 a.target = this.target;
1643 return (this.href) ? a : cfg;
1646 initEvents: function()
1649 this.el.on('click', this.onClick, this);
1654 onClick : function(e)
1656 Roo.log('img onclick');
1657 this.fireEvent('click', this, e);
1660 * Sets the url of the image - used to update it
1661 * @param {String} url the url of the image
1664 setSrc : function(url)
1668 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1669 this.el.dom.src = url;
1673 this.el.select('img', true).first().dom.src = url;
1689 * @class Roo.bootstrap.Link
1690 * @extends Roo.bootstrap.Component
1691 * Bootstrap Link Class
1692 * @cfg {String} alt image alternative text
1693 * @cfg {String} href a tag href
1694 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1695 * @cfg {String} html the content of the link.
1696 * @cfg {String} anchor name for the anchor link
1697 * @cfg {String} fa - favicon
1699 * @cfg {Boolean} preventDefault (true | false) default false
1703 * Create a new Input
1704 * @param {Object} config The config object
1707 Roo.bootstrap.Link = function(config){
1708 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1714 * The img click event for the img.
1715 * @param {Roo.EventObject} e
1721 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1725 preventDefault: false,
1731 getAutoCreate : function()
1733 var html = this.html || '';
1735 if (this.fa !== false) {
1736 html = '<i class="fa fa-' + this.fa + '"></i>';
1741 // anchor's do not require html/href...
1742 if (this.anchor === false) {
1744 cfg.href = this.href || '#';
1746 cfg.name = this.anchor;
1747 if (this.html !== false || this.fa !== false) {
1750 if (this.href !== false) {
1751 cfg.href = this.href;
1755 if(this.alt !== false){
1760 if(this.target !== false) {
1761 cfg.target = this.target;
1767 initEvents: function() {
1769 if(!this.href || this.preventDefault){
1770 this.el.on('click', this.onClick, this);
1774 onClick : function(e)
1776 if(this.preventDefault){
1779 //Roo.log('img onclick');
1780 this.fireEvent('click', this, e);
1793 * @class Roo.bootstrap.Header
1794 * @extends Roo.bootstrap.Component
1795 * Bootstrap Header class
1796 * @cfg {String} html content of header
1797 * @cfg {Number} level (1|2|3|4|5|6) default 1
1800 * Create a new Header
1801 * @param {Object} config The config object
1805 Roo.bootstrap.Header = function(config){
1806 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1809 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1817 getAutoCreate : function(){
1822 tag: 'h' + (1 *this.level),
1823 html: this.html || ''
1835 * Ext JS Library 1.1.1
1836 * Copyright(c) 2006-2007, Ext JS, LLC.
1838 * Originally Released Under LGPL - original licence link has changed is not relivant.
1841 * <script type="text/javascript">
1845 * @class Roo.bootstrap.MenuMgr
1846 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1849 Roo.bootstrap.MenuMgr = function(){
1850 var menus, active, groups = {}, attached = false, lastShow = new Date();
1852 // private - called when first menu is created
1855 active = new Roo.util.MixedCollection();
1856 Roo.get(document).addKeyListener(27, function(){
1857 if(active.length > 0){
1865 if(active && active.length > 0){
1866 var c = active.clone();
1876 if(active.length < 1){
1877 Roo.get(document).un("mouseup", onMouseDown);
1885 var last = active.last();
1886 lastShow = new Date();
1889 Roo.get(document).on("mouseup", onMouseDown);
1894 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1895 m.parentMenu.activeChild = m;
1896 }else if(last && last.isVisible()){
1897 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1902 function onBeforeHide(m){
1904 m.activeChild.hide();
1906 if(m.autoHideTimer){
1907 clearTimeout(m.autoHideTimer);
1908 delete m.autoHideTimer;
1913 function onBeforeShow(m){
1914 var pm = m.parentMenu;
1915 if(!pm && !m.allowOtherMenus){
1917 }else if(pm && pm.activeChild && active != m){
1918 pm.activeChild.hide();
1922 // private this should really trigger on mouseup..
1923 function onMouseDown(e){
1924 Roo.log("on Mouse Up");
1926 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1927 Roo.log("MenuManager hideAll");
1936 function onBeforeCheck(mi, state){
1938 var g = groups[mi.group];
1939 for(var i = 0, l = g.length; i < l; i++){
1941 g[i].setChecked(false);
1950 * Hides all menus that are currently visible
1952 hideAll : function(){
1957 register : function(menu){
1961 menus[menu.id] = menu;
1962 menu.on("beforehide", onBeforeHide);
1963 menu.on("hide", onHide);
1964 menu.on("beforeshow", onBeforeShow);
1965 menu.on("show", onShow);
1967 if(g && menu.events["checkchange"]){
1971 groups[g].push(menu);
1972 menu.on("checkchange", onCheck);
1977 * Returns a {@link Roo.menu.Menu} object
1978 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1979 * be used to generate and return a new Menu instance.
1981 get : function(menu){
1982 if(typeof menu == "string"){ // menu id
1984 }else if(menu.events){ // menu instance
1987 /*else if(typeof menu.length == 'number'){ // array of menu items?
1988 return new Roo.bootstrap.Menu({items:menu});
1989 }else{ // otherwise, must be a config
1990 return new Roo.bootstrap.Menu(menu);
1997 unregister : function(menu){
1998 delete menus[menu.id];
1999 menu.un("beforehide", onBeforeHide);
2000 menu.un("hide", onHide);
2001 menu.un("beforeshow", onBeforeShow);
2002 menu.un("show", onShow);
2004 if(g && menu.events["checkchange"]){
2005 groups[g].remove(menu);
2006 menu.un("checkchange", onCheck);
2011 registerCheckable : function(menuItem){
2012 var g = menuItem.group;
2017 groups[g].push(menuItem);
2018 menuItem.on("beforecheckchange", onBeforeCheck);
2023 unregisterCheckable : function(menuItem){
2024 var g = menuItem.group;
2026 groups[g].remove(menuItem);
2027 menuItem.un("beforecheckchange", onBeforeCheck);
2039 * @class Roo.bootstrap.Menu
2040 * @extends Roo.bootstrap.Component
2041 * Bootstrap Menu class - container for MenuItems
2042 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2043 * @cfg {bool} hidden if the menu should be hidden when rendered.
2044 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2045 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2049 * @param {Object} config The config object
2053 Roo.bootstrap.Menu = function(config){
2054 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2055 if (this.registerMenu && this.type != 'treeview') {
2056 Roo.bootstrap.MenuMgr.register(this);
2063 * Fires before this menu is displayed
2064 * @param {Roo.menu.Menu} this
2069 * Fires before this menu is hidden
2070 * @param {Roo.menu.Menu} this
2075 * Fires after this menu is displayed
2076 * @param {Roo.menu.Menu} this
2081 * Fires after this menu is hidden
2082 * @param {Roo.menu.Menu} this
2087 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2088 * @param {Roo.menu.Menu} this
2089 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2090 * @param {Roo.EventObject} e
2095 * Fires when the mouse is hovering over this menu
2096 * @param {Roo.menu.Menu} this
2097 * @param {Roo.EventObject} e
2098 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2103 * Fires when the mouse exits this menu
2104 * @param {Roo.menu.Menu} this
2105 * @param {Roo.EventObject} e
2106 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2111 * Fires when a menu item contained in this menu is clicked
2112 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2113 * @param {Roo.EventObject} e
2117 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2120 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2124 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2127 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2129 registerMenu : true,
2131 menuItems :false, // stores the menu items..
2141 getChildContainer : function() {
2145 getAutoCreate : function(){
2147 //if (['right'].indexOf(this.align)!==-1) {
2148 // cfg.cn[1].cls += ' pull-right'
2154 cls : 'dropdown-menu' ,
2155 style : 'z-index:1000'
2159 if (this.type === 'submenu') {
2160 cfg.cls = 'submenu active';
2162 if (this.type === 'treeview') {
2163 cfg.cls = 'treeview-menu';
2168 initEvents : function() {
2170 // Roo.log("ADD event");
2171 // Roo.log(this.triggerEl.dom);
2173 this.triggerEl.on('click', this.onTriggerClick, this);
2175 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2178 if (this.triggerEl.hasClass('nav-item')) {
2179 // dropdown toggle on the 'a' in BS4?
2180 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2182 this.triggerEl.addClass('dropdown-toggle');
2185 this.el.on('touchstart' , this.onTouch, this);
2187 this.el.on('click' , this.onClick, this);
2189 this.el.on("mouseover", this.onMouseOver, this);
2190 this.el.on("mouseout", this.onMouseOut, this);
2194 findTargetItem : function(e)
2196 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2200 //Roo.log(t); Roo.log(t.id);
2202 //Roo.log(this.menuitems);
2203 return this.menuitems.get(t.id);
2205 //return this.items.get(t.menuItemId);
2211 onTouch : function(e)
2213 Roo.log("menu.onTouch");
2214 //e.stopEvent(); this make the user popdown broken
2218 onClick : function(e)
2220 Roo.log("menu.onClick");
2222 var t = this.findTargetItem(e);
2223 if(!t || t.isContainer){
2228 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2229 if(t == this.activeItem && t.shouldDeactivate(e)){
2230 this.activeItem.deactivate();
2231 delete this.activeItem;
2235 this.setActiveItem(t, true);
2243 Roo.log('pass click event');
2247 this.fireEvent("click", this, t, e);
2251 if(!t.href.length || t.href == '#'){
2252 (function() { _this.hide(); }).defer(100);
2257 onMouseOver : function(e){
2258 var t = this.findTargetItem(e);
2261 // if(t.canActivate && !t.disabled){
2262 // this.setActiveItem(t, true);
2266 this.fireEvent("mouseover", this, e, t);
2268 isVisible : function(){
2269 return !this.hidden;
2271 onMouseOut : function(e){
2272 var t = this.findTargetItem(e);
2275 // if(t == this.activeItem && t.shouldDeactivate(e)){
2276 // this.activeItem.deactivate();
2277 // delete this.activeItem;
2280 this.fireEvent("mouseout", this, e, t);
2285 * Displays this menu relative to another element
2286 * @param {String/HTMLElement/Roo.Element} element The element to align to
2287 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2288 * the element (defaults to this.defaultAlign)
2289 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2291 show : function(el, pos, parentMenu){
2292 this.parentMenu = parentMenu;
2296 this.fireEvent("beforeshow", this);
2297 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2300 * Displays this menu at a specific xy position
2301 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2302 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2304 showAt : function(xy, parentMenu, /* private: */_e){
2305 this.parentMenu = parentMenu;
2310 this.fireEvent("beforeshow", this);
2311 //xy = this.el.adjustForConstraints(xy);
2315 this.hideMenuItems();
2316 this.hidden = false;
2317 this.triggerEl.addClass('open');
2318 this.el.addClass('show');
2320 // reassign x when hitting right
2321 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2322 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2325 // reassign y when hitting bottom
2326 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2327 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2330 // but the list may align on trigger left or trigger top... should it be a properity?
2332 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2337 this.fireEvent("show", this);
2343 this.doFocus.defer(50, this);
2347 doFocus : function(){
2349 this.focusEl.focus();
2354 * Hides this menu and optionally all parent menus
2355 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2357 hide : function(deep)
2360 this.hideMenuItems();
2361 if(this.el && this.isVisible()){
2362 this.fireEvent("beforehide", this);
2363 if(this.activeItem){
2364 this.activeItem.deactivate();
2365 this.activeItem = null;
2367 this.triggerEl.removeClass('open');;
2368 this.el.removeClass('show');
2370 this.fireEvent("hide", this);
2372 if(deep === true && this.parentMenu){
2373 this.parentMenu.hide(true);
2377 onTriggerClick : function(e)
2379 Roo.log('trigger click');
2381 var target = e.getTarget();
2383 Roo.log(target.nodeName.toLowerCase());
2385 if(target.nodeName.toLowerCase() === 'i'){
2391 onTriggerPress : function(e)
2393 Roo.log('trigger press');
2394 //Roo.log(e.getTarget());
2395 // Roo.log(this.triggerEl.dom);
2397 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2398 var pel = Roo.get(e.getTarget());
2399 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2400 Roo.log('is treeview or dropdown?');
2404 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2408 if (this.isVisible()) {
2413 this.show(this.triggerEl, '?', false);
2416 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2423 hideMenuItems : function()
2425 Roo.log("hide Menu Items");
2429 //$(backdrop).remove()
2430 this.el.select('.open',true).each(function(aa) {
2432 aa.removeClass('open');
2433 //var parent = getParent($(this))
2434 //var relatedTarget = { relatedTarget: this }
2436 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2437 //if (e.isDefaultPrevented()) return
2438 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2441 addxtypeChild : function (tree, cntr) {
2442 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2444 this.menuitems.add(comp);
2456 this.getEl().dom.innerHTML = '';
2457 this.menuitems.clear();
2471 * @class Roo.bootstrap.MenuItem
2472 * @extends Roo.bootstrap.Component
2473 * Bootstrap MenuItem class
2474 * @cfg {String} html the menu label
2475 * @cfg {String} href the link
2476 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2477 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2478 * @cfg {Boolean} active used on sidebars to highlight active itesm
2479 * @cfg {String} fa favicon to show on left of menu item.
2480 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2484 * Create a new MenuItem
2485 * @param {Object} config The config object
2489 Roo.bootstrap.MenuItem = function(config){
2490 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2495 * The raw click event for the entire grid.
2496 * @param {Roo.bootstrap.MenuItem} this
2497 * @param {Roo.EventObject} e
2503 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2507 preventDefault: false,
2508 isContainer : false,
2512 getAutoCreate : function(){
2514 if(this.isContainer){
2517 cls: 'dropdown-menu-item '
2527 cls : 'dropdown-item',
2532 if (this.fa !== false) {
2535 cls : 'fa fa-' + this.fa
2544 cls: 'dropdown-menu-item',
2547 if (this.parent().type == 'treeview') {
2548 cfg.cls = 'treeview-menu';
2551 cfg.cls += ' active';
2556 anc.href = this.href || cfg.cn[0].href ;
2557 ctag.html = this.html || cfg.cn[0].html ;
2561 initEvents: function()
2563 if (this.parent().type == 'treeview') {
2564 this.el.select('a').on('click', this.onClick, this);
2568 this.menu.parentType = this.xtype;
2569 this.menu.triggerEl = this.el;
2570 this.menu = this.addxtype(Roo.apply({}, this.menu));
2574 onClick : function(e)
2576 Roo.log('item on click ');
2578 if(this.preventDefault){
2581 //this.parent().hideMenuItems();
2583 this.fireEvent('click', this, e);
2602 * @class Roo.bootstrap.MenuSeparator
2603 * @extends Roo.bootstrap.Component
2604 * Bootstrap MenuSeparator class
2607 * Create a new MenuItem
2608 * @param {Object} config The config object
2612 Roo.bootstrap.MenuSeparator = function(config){
2613 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2616 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2618 getAutoCreate : function(){
2637 * @class Roo.bootstrap.Modal
2638 * @extends Roo.bootstrap.Component
2639 * Bootstrap Modal class
2640 * @cfg {String} title Title of dialog
2641 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2642 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2643 * @cfg {Boolean} specificTitle default false
2644 * @cfg {Array} buttons Array of buttons or standard button set..
2645 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2646 * @cfg {Boolean} animate default true
2647 * @cfg {Boolean} allow_close default true
2648 * @cfg {Boolean} fitwindow default false
2649 * @cfg {String} size (sm|lg) default empty
2650 * @cfg {Number} max_width set the max width of modal
2654 * Create a new Modal Dialog
2655 * @param {Object} config The config object
2658 Roo.bootstrap.Modal = function(config){
2659 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2664 * The raw btnclick event for the button
2665 * @param {Roo.EventObject} e
2670 * Fire when dialog resize
2671 * @param {Roo.bootstrap.Modal} this
2672 * @param {Roo.EventObject} e
2676 this.buttons = this.buttons || [];
2679 this.tmpl = Roo.factory(this.tmpl);
2684 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2686 title : 'test dialog',
2696 specificTitle: false,
2698 buttonPosition: 'right',
2721 onRender : function(ct, position)
2723 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2726 var cfg = Roo.apply({}, this.getAutoCreate());
2729 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2731 //if (!cfg.name.length) {
2735 cfg.cls += ' ' + this.cls;
2738 cfg.style = this.style;
2740 this.el = Roo.get(document.body).createChild(cfg, position);
2742 //var type = this.el.dom.type;
2745 if(this.tabIndex !== undefined){
2746 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2749 this.dialogEl = this.el.select('.modal-dialog',true).first();
2750 this.bodyEl = this.el.select('.modal-body',true).first();
2751 this.closeEl = this.el.select('.modal-header .close', true).first();
2752 this.headerEl = this.el.select('.modal-header',true).first();
2753 this.titleEl = this.el.select('.modal-title',true).first();
2754 this.footerEl = this.el.select('.modal-footer',true).first();
2756 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2758 //this.el.addClass("x-dlg-modal");
2760 if (this.buttons.length) {
2761 Roo.each(this.buttons, function(bb) {
2762 var b = Roo.apply({}, bb);
2763 b.xns = b.xns || Roo.bootstrap;
2764 b.xtype = b.xtype || 'Button';
2765 if (typeof(b.listeners) == 'undefined') {
2766 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2769 var btn = Roo.factory(b);
2771 btn.render(this.getButtonContainer());
2775 // render the children.
2778 if(typeof(this.items) != 'undefined'){
2779 var items = this.items;
2782 for(var i =0;i < items.length;i++) {
2783 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2787 this.items = nitems;
2789 // where are these used - they used to be body/close/footer
2793 //this.el.addClass([this.fieldClass, this.cls]);
2797 getAutoCreate : function()
2801 html : this.html || ''
2806 cls : 'modal-title',
2810 if(this.specificTitle){
2816 if (this.allow_close && Roo.bootstrap.version == 3) {
2826 if (this.allow_close && Roo.bootstrap.version == 4) {
2836 if(this.size.length){
2837 size = 'modal-' + this.size;
2840 var footer = Roo.bootstrap.version == 3 ?
2842 cls : 'modal-footer',
2846 cls: 'btn-' + this.buttonPosition
2851 { // BS4 uses mr-auto on left buttons....
2852 cls : 'modal-footer'
2863 cls: "modal-dialog " + size,
2866 cls : "modal-content",
2869 cls : 'modal-header',
2884 modal.cls += ' fade';
2890 getChildContainer : function() {
2895 getButtonContainer : function() {
2897 return Roo.bootstrap.version == 4 ?
2898 this.el.select('.modal-footer',true).first()
2899 : this.el.select('.modal-footer div',true).first();
2902 initEvents : function()
2904 if (this.allow_close) {
2905 this.closeEl.on('click', this.hide, this);
2907 Roo.EventManager.onWindowResize(this.resize, this, true);
2915 this.maskEl.setSize(
2916 Roo.lib.Dom.getViewWidth(true),
2917 Roo.lib.Dom.getViewHeight(true)
2920 if (this.fitwindow) {
2924 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2925 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
2930 if(this.max_width !== 0) {
2932 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2935 this.setSize(w, this.height);
2939 if(this.max_height) {
2940 this.setSize(w,Math.min(
2942 Roo.lib.Dom.getViewportHeight(true) - 60
2948 if(!this.fit_content) {
2949 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2953 this.setSize(w, Math.min(
2955 this.headerEl.getHeight() +
2956 this.footerEl.getHeight() +
2957 this.getChildHeight(this.bodyEl.dom.childNodes),
2958 Roo.lib.Dom.getViewportHeight(true) - 60)
2964 setSize : function(w,h)
2975 if (!this.rendered) {
2979 //this.el.setStyle('display', 'block');
2980 this.el.removeClass('hideing');
2981 this.el.dom.style.display='block';
2983 Roo.get(document.body).addClass('modal-open');
2985 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2988 this.el.addClass('show');
2989 this.el.addClass('in');
2992 this.el.addClass('show');
2993 this.el.addClass('in');
2996 // not sure how we can show data in here..
2998 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3001 Roo.get(document.body).addClass("x-body-masked");
3003 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3004 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3005 this.maskEl.dom.style.display = 'block';
3006 this.maskEl.addClass('show');
3011 this.fireEvent('show', this);
3013 // set zindex here - otherwise it appears to be ignored...
3014 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3017 this.items.forEach( function(e) {
3018 e.layout ? e.layout() : false;
3026 if(this.fireEvent("beforehide", this) !== false){
3028 this.maskEl.removeClass('show');
3030 this.maskEl.dom.style.display = '';
3031 Roo.get(document.body).removeClass("x-body-masked");
3032 this.el.removeClass('in');
3033 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3035 if(this.animate){ // why
3036 this.el.addClass('hideing');
3037 this.el.removeClass('show');
3039 if (!this.el.hasClass('hideing')) {
3040 return; // it's been shown again...
3043 this.el.dom.style.display='';
3045 Roo.get(document.body).removeClass('modal-open');
3046 this.el.removeClass('hideing');
3050 this.el.removeClass('show');
3051 this.el.dom.style.display='';
3052 Roo.get(document.body).removeClass('modal-open');
3055 this.fireEvent('hide', this);
3058 isVisible : function()
3061 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3065 addButton : function(str, cb)
3069 var b = Roo.apply({}, { html : str } );
3070 b.xns = b.xns || Roo.bootstrap;
3071 b.xtype = b.xtype || 'Button';
3072 if (typeof(b.listeners) == 'undefined') {
3073 b.listeners = { click : cb.createDelegate(this) };
3076 var btn = Roo.factory(b);
3078 btn.render(this.getButtonContainer());
3084 setDefaultButton : function(btn)
3086 //this.el.select('.modal-footer').()
3089 resizeTo: function(w,h)
3091 this.dialogEl.setWidth(w);
3093 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
3095 this.bodyEl.setHeight(h - diff);
3097 this.fireEvent('resize', this);
3100 setContentSize : function(w, h)
3104 onButtonClick: function(btn,e)
3107 this.fireEvent('btnclick', btn.name, e);
3110 * Set the title of the Dialog
3111 * @param {String} str new Title
3113 setTitle: function(str) {
3114 this.titleEl.dom.innerHTML = str;
3117 * Set the body of the Dialog
3118 * @param {String} str new Title
3120 setBody: function(str) {
3121 this.bodyEl.dom.innerHTML = str;
3124 * Set the body of the Dialog using the template
3125 * @param {Obj} data - apply this data to the template and replace the body contents.
3127 applyBody: function(obj)
3130 Roo.log("Error - using apply Body without a template");
3133 this.tmpl.overwrite(this.bodyEl, obj);
3136 getChildHeight : function(child_nodes)
3140 child_nodes.length == 0
3145 var child_height = 0;
3147 for(var i = 0; i < child_nodes.length; i++) {
3150 * for modal with tabs...
3151 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3153 var layout_childs = child_nodes[i].childNodes;
3155 for(var j = 0; j < layout_childs.length; j++) {
3157 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3159 var layout_body_childs = layout_childs[j].childNodes;
3161 for(var k = 0; k < layout_body_childs.length; k++) {
3163 if(layout_body_childs[k].classList.contains('navbar')) {
3164 child_height += layout_body_childs[k].offsetHeight;
3168 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3170 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3172 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3174 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3175 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3190 child_height += child_nodes[i].offsetHeight;
3191 // Roo.log(child_nodes[i].offsetHeight);
3194 return child_height;
3200 Roo.apply(Roo.bootstrap.Modal, {
3202 * Button config that displays a single OK button
3211 * Button config that displays Yes and No buttons
3227 * Button config that displays OK and Cancel buttons
3242 * Button config that displays Yes, No and Cancel buttons
3266 * messagebox - can be used as a replace
3270 * @class Roo.MessageBox
3271 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3275 Roo.Msg.alert('Status', 'Changes saved successfully.');
3277 // Prompt for user data:
3278 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3280 // process text value...
3284 // Show a dialog using config options:
3286 title:'Save Changes?',
3287 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3288 buttons: Roo.Msg.YESNOCANCEL,
3295 Roo.bootstrap.MessageBox = function(){
3296 var dlg, opt, mask, waitTimer;
3297 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3298 var buttons, activeTextEl, bwidth;
3302 var handleButton = function(button){
3304 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3308 var handleHide = function(){
3310 dlg.el.removeClass(opt.cls);
3313 // Roo.TaskMgr.stop(waitTimer);
3314 // waitTimer = null;
3319 var updateButtons = function(b){
3322 buttons["ok"].hide();
3323 buttons["cancel"].hide();
3324 buttons["yes"].hide();
3325 buttons["no"].hide();
3326 dlg.footerEl.hide();
3330 dlg.footerEl.show();
3331 for(var k in buttons){
3332 if(typeof buttons[k] != "function"){
3335 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3336 width += buttons[k].el.getWidth()+15;
3346 var handleEsc = function(d, k, e){
3347 if(opt && opt.closable !== false){
3357 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3358 * @return {Roo.BasicDialog} The BasicDialog element
3360 getDialog : function(){
3362 dlg = new Roo.bootstrap.Modal( {
3365 //constraintoviewport:false,
3367 //collapsible : false,
3372 //buttonAlign:"center",
3373 closeClick : function(){
3374 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3377 handleButton("cancel");
3382 dlg.on("hide", handleHide);
3384 //dlg.addKeyListener(27, handleEsc);
3386 this.buttons = buttons;
3387 var bt = this.buttonText;
3388 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3389 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3390 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3391 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3393 bodyEl = dlg.bodyEl.createChild({
3395 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3396 '<textarea class="roo-mb-textarea"></textarea>' +
3397 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3399 msgEl = bodyEl.dom.firstChild;
3400 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3401 textboxEl.enableDisplayMode();
3402 textboxEl.addKeyListener([10,13], function(){
3403 if(dlg.isVisible() && opt && opt.buttons){
3406 }else if(opt.buttons.yes){
3407 handleButton("yes");
3411 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3412 textareaEl.enableDisplayMode();
3413 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3414 progressEl.enableDisplayMode();
3416 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3417 var pf = progressEl.dom.firstChild;
3419 pp = Roo.get(pf.firstChild);
3420 pp.setHeight(pf.offsetHeight);
3428 * Updates the message box body text
3429 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3430 * the XHTML-compliant non-breaking space character '&#160;')
3431 * @return {Roo.MessageBox} This message box
3433 updateText : function(text)
3435 if(!dlg.isVisible() && !opt.width){
3436 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3437 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3439 msgEl.innerHTML = text || ' ';
3441 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3442 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3444 Math.min(opt.width || cw , this.maxWidth),
3445 Math.max(opt.minWidth || this.minWidth, bwidth)
3448 activeTextEl.setWidth(w);
3450 if(dlg.isVisible()){
3451 dlg.fixedcenter = false;
3453 // to big, make it scroll. = But as usual stupid IE does not support
3456 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3457 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3458 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3460 bodyEl.dom.style.height = '';
3461 bodyEl.dom.style.overflowY = '';
3464 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3466 bodyEl.dom.style.overflowX = '';
3469 dlg.setContentSize(w, bodyEl.getHeight());
3470 if(dlg.isVisible()){
3471 dlg.fixedcenter = true;
3477 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3478 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3479 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3480 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3481 * @return {Roo.MessageBox} This message box
3483 updateProgress : function(value, text){
3485 this.updateText(text);
3488 if (pp) { // weird bug on my firefox - for some reason this is not defined
3489 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3490 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3496 * Returns true if the message box is currently displayed
3497 * @return {Boolean} True if the message box is visible, else false
3499 isVisible : function(){
3500 return dlg && dlg.isVisible();
3504 * Hides the message box if it is displayed
3507 if(this.isVisible()){
3513 * Displays a new message box, or reinitializes an existing message box, based on the config options
3514 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3515 * The following config object properties are supported:
3517 Property Type Description
3518 ---------- --------------- ------------------------------------------------------------------------------------
3519 animEl String/Element An id or Element from which the message box should animate as it opens and
3520 closes (defaults to undefined)
3521 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3522 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3523 closable Boolean False to hide the top-right close button (defaults to true). Note that
3524 progress and wait dialogs will ignore this property and always hide the
3525 close button as they can only be closed programmatically.
3526 cls String A custom CSS class to apply to the message box element
3527 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3528 displayed (defaults to 75)
3529 fn Function A callback function to execute after closing the dialog. The arguments to the
3530 function will be btn (the name of the button that was clicked, if applicable,
3531 e.g. "ok"), and text (the value of the active text field, if applicable).
3532 Progress and wait dialogs will ignore this option since they do not respond to
3533 user actions and can only be closed programmatically, so any required function
3534 should be called by the same code after it closes the dialog.
3535 icon String A CSS class that provides a background image to be used as an icon for
3536 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3537 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3538 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3539 modal Boolean False to allow user interaction with the page while the message box is
3540 displayed (defaults to true)
3541 msg String A string that will replace the existing message box body text (defaults
3542 to the XHTML-compliant non-breaking space character ' ')
3543 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3544 progress Boolean True to display a progress bar (defaults to false)
3545 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3546 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3547 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3548 title String The title text
3549 value String The string value to set into the active textbox element if displayed
3550 wait Boolean True to display a progress bar (defaults to false)
3551 width Number The width of the dialog in pixels
3558 msg: 'Please enter your address:',
3560 buttons: Roo.MessageBox.OKCANCEL,
3563 animEl: 'addAddressBtn'
3566 * @param {Object} config Configuration options
3567 * @return {Roo.MessageBox} This message box
3569 show : function(options)
3572 // this causes nightmares if you show one dialog after another
3573 // especially on callbacks..
3575 if(this.isVisible()){
3578 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3579 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3580 Roo.log("New Dialog Message:" + options.msg )
3581 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3582 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3585 var d = this.getDialog();
3587 d.setTitle(opt.title || " ");
3588 d.closeEl.setDisplayed(opt.closable !== false);
3589 activeTextEl = textboxEl;
3590 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3595 textareaEl.setHeight(typeof opt.multiline == "number" ?
3596 opt.multiline : this.defaultTextHeight);
3597 activeTextEl = textareaEl;
3606 progressEl.setDisplayed(opt.progress === true);
3608 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3610 this.updateProgress(0);
3611 activeTextEl.dom.value = opt.value || "";
3613 dlg.setDefaultButton(activeTextEl);
3615 var bs = opt.buttons;
3619 }else if(bs && bs.yes){
3620 db = buttons["yes"];
3622 dlg.setDefaultButton(db);
3624 bwidth = updateButtons(opt.buttons);
3625 this.updateText(opt.msg);
3627 d.el.addClass(opt.cls);
3629 d.proxyDrag = opt.proxyDrag === true;
3630 d.modal = opt.modal !== false;
3631 d.mask = opt.modal !== false ? mask : false;
3633 // force it to the end of the z-index stack so it gets a cursor in FF
3634 document.body.appendChild(dlg.el.dom);
3635 d.animateTarget = null;
3636 d.show(options.animEl);
3642 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3643 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3644 * and closing the message box when the process is complete.
3645 * @param {String} title The title bar text
3646 * @param {String} msg The message box body text
3647 * @return {Roo.MessageBox} This message box
3649 progress : function(title, msg){
3656 minWidth: this.minProgressWidth,
3663 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3664 * If a callback function is passed it will be called after the user clicks the button, and the
3665 * id of the button that was clicked will be passed as the only parameter to the callback
3666 * (could also be the top-right close button).
3667 * @param {String} title The title bar text
3668 * @param {String} msg The message box body text
3669 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3670 * @param {Object} scope (optional) The scope of the callback function
3671 * @return {Roo.MessageBox} This message box
3673 alert : function(title, msg, fn, scope)
3688 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3689 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3690 * You are responsible for closing the message box when the process is complete.
3691 * @param {String} msg The message box body text
3692 * @param {String} title (optional) The title bar text
3693 * @return {Roo.MessageBox} This message box
3695 wait : function(msg, title){
3706 waitTimer = Roo.TaskMgr.start({
3708 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3716 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3717 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3718 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3719 * @param {String} title The title bar text
3720 * @param {String} msg The message box body text
3721 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3722 * @param {Object} scope (optional) The scope of the callback function
3723 * @return {Roo.MessageBox} This message box
3725 confirm : function(title, msg, fn, scope){
3729 buttons: this.YESNO,
3738 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3739 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3740 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3741 * (could also be the top-right close button) and the text that was entered will be passed as the two
3742 * parameters to the callback.
3743 * @param {String} title The title bar text
3744 * @param {String} msg The message box body text
3745 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3746 * @param {Object} scope (optional) The scope of the callback function
3747 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3748 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3749 * @return {Roo.MessageBox} This message box
3751 prompt : function(title, msg, fn, scope, multiline){
3755 buttons: this.OKCANCEL,
3760 multiline: multiline,
3767 * Button config that displays a single OK button
3772 * Button config that displays Yes and No buttons
3775 YESNO : {yes:true, no:true},
3777 * Button config that displays OK and Cancel buttons
3780 OKCANCEL : {ok:true, cancel:true},
3782 * Button config that displays Yes, No and Cancel buttons
3785 YESNOCANCEL : {yes:true, no:true, cancel:true},
3788 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3791 defaultTextHeight : 75,
3793 * The maximum width in pixels of the message box (defaults to 600)
3798 * The minimum width in pixels of the message box (defaults to 100)
3803 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3804 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3807 minProgressWidth : 250,
3809 * An object containing the default button text strings that can be overriden for localized language support.
3810 * Supported properties are: ok, cancel, yes and no.
3811 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3824 * Shorthand for {@link Roo.MessageBox}
3826 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3827 Roo.Msg = Roo.Msg || Roo.MessageBox;
3836 * @class Roo.bootstrap.Navbar
3837 * @extends Roo.bootstrap.Component
3838 * Bootstrap Navbar class
3841 * Create a new Navbar
3842 * @param {Object} config The config object
3846 Roo.bootstrap.Navbar = function(config){
3847 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3851 * @event beforetoggle
3852 * Fire before toggle the menu
3853 * @param {Roo.EventObject} e
3855 "beforetoggle" : true
3859 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3868 getAutoCreate : function(){
3871 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3875 initEvents :function ()
3877 //Roo.log(this.el.select('.navbar-toggle',true));
3878 this.el.select('.navbar-toggle',true).on('click', function() {
3879 if(this.fireEvent('beforetoggle', this) !== false){
3880 var ce = this.el.select('.navbar-collapse',true).first();
3881 ce.toggleClass('in'); // old...
3882 if (ce.hasClass('collapse')) {
3884 ce.removeClass('collapse');
3885 ce.addClass('show');
3886 var h = ce.getHeight();
3888 ce.removeClass('show');
3889 // at this point we should be able to see it..
3890 ce.addClass('collapsing');
3892 ce.setHeight(0); // resize it ...
3893 ce.on('transitionend', function() {
3894 Roo.log('done transition');
3895 ce.removeClass('collapsing');
3896 ce.addClass('show');
3897 ce.removeClass('collapse');
3899 ce.dom.style.height = '';
3900 }, this, { single: true} );
3904 ce.setHeight(ce.getHeight());
3905 ce.removeClass('show');
3906 ce.addClass('collapsing');
3908 ce.on('transitionend', function() {
3909 ce.dom.style.height = '';
3910 ce.removeClass('collapsing');
3911 ce.addClass('collapse');
3912 }, this, { single: true} );
3924 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3926 var size = this.el.getSize();
3927 this.maskEl.setSize(size.width, size.height);
3928 this.maskEl.enableDisplayMode("block");
3937 getChildContainer : function()
3939 if (this.el && this.el.select('.collapse').getCount()) {
3940 return this.el.select('.collapse',true).first();
3973 * @class Roo.bootstrap.NavSimplebar
3974 * @extends Roo.bootstrap.Navbar
3975 * Bootstrap Sidebar class
3977 * @cfg {Boolean} inverse is inverted color
3979 * @cfg {String} type (nav | pills | tabs)
3980 * @cfg {Boolean} arrangement stacked | justified
3981 * @cfg {String} align (left | right) alignment
3983 * @cfg {Boolean} main (true|false) main nav bar? default false
3984 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3986 * @cfg {String} tag (header|footer|nav|div) default is nav
3988 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
3992 * Create a new Sidebar
3993 * @param {Object} config The config object
3997 Roo.bootstrap.NavSimplebar = function(config){
3998 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4001 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4017 getAutoCreate : function(){
4021 tag : this.tag || 'div',
4022 cls : 'navbar navbar-expand-lg roo-navbar-simple'
4024 if (['light','white'].indexOf(this.weight) > -1) {
4025 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4027 cfg.cls += ' bg-' + this.weight;
4030 cfg.cls += ' navbar-inverse';
4034 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4036 //if (Roo.bootstrap.version == 4) {
4048 this.type = this.type || 'nav';
4049 if (['tabs','pills'].indexOf(this.type) != -1) {
4050 cfg.cn[0].cls += ' nav-' + this.type
4054 if (this.type!=='nav') {
4055 Roo.log('nav type must be nav/tabs/pills')
4057 cfg.cn[0].cls += ' navbar-nav'
4063 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4064 cfg.cn[0].cls += ' nav-' + this.arrangement;
4068 if (this.align === 'right') {
4069 cfg.cn[0].cls += ' navbar-right';
4094 * navbar-expand-md fixed-top
4098 * @class Roo.bootstrap.NavHeaderbar
4099 * @extends Roo.bootstrap.NavSimplebar
4100 * Bootstrap Sidebar class
4102 * @cfg {String} brand what is brand
4103 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4104 * @cfg {String} brand_href href of the brand
4105 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4106 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4107 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4108 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4111 * Create a new Sidebar
4112 * @param {Object} config The config object
4116 Roo.bootstrap.NavHeaderbar = function(config){
4117 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4121 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4128 desktopCenter : false,
4131 getAutoCreate : function(){
4134 tag: this.nav || 'nav',
4135 cls: 'navbar navbar-expand-md',
4141 if (this.desktopCenter) {
4142 cn.push({cls : 'container', cn : []});
4150 cls: 'navbar-toggle navbar-toggler',
4151 'data-toggle': 'collapse',
4156 html: 'Toggle navigation'
4160 cls: 'icon-bar navbar-toggler-icon'
4173 cn.push( Roo.bootstrap.version == 4 ? btn : {
4175 cls: 'navbar-header',
4184 cls: 'collapse navbar-collapse',
4188 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4190 if (['light','white'].indexOf(this.weight) > -1) {
4191 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4193 cfg.cls += ' bg-' + this.weight;
4196 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4197 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4199 // tag can override this..
4201 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4204 if (this.brand !== '') {
4205 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4206 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4208 href: this.brand_href ? this.brand_href : '#',
4209 cls: 'navbar-brand',
4217 cfg.cls += ' main-nav';
4225 getHeaderChildContainer : function()
4227 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4228 return this.el.select('.navbar-header',true).first();
4231 return this.getChildContainer();
4235 initEvents : function()
4237 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4239 if (this.autohide) {
4244 Roo.get(document).on('scroll',function(e) {
4245 var ns = Roo.get(document).getScroll().top;
4246 var os = prevScroll;
4250 ft.removeClass('slideDown');
4251 ft.addClass('slideUp');
4254 ft.removeClass('slideUp');
4255 ft.addClass('slideDown');
4276 * @class Roo.bootstrap.NavSidebar
4277 * @extends Roo.bootstrap.Navbar
4278 * Bootstrap Sidebar class
4281 * Create a new Sidebar
4282 * @param {Object} config The config object
4286 Roo.bootstrap.NavSidebar = function(config){
4287 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4290 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4292 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4294 getAutoCreate : function(){
4299 cls: 'sidebar sidebar-nav'
4321 * @class Roo.bootstrap.NavGroup
4322 * @extends Roo.bootstrap.Component
4323 * Bootstrap NavGroup class
4324 * @cfg {String} align (left|right)
4325 * @cfg {Boolean} inverse
4326 * @cfg {String} type (nav|pills|tab) default nav
4327 * @cfg {String} navId - reference Id for navbar.
4331 * Create a new nav group
4332 * @param {Object} config The config object
4335 Roo.bootstrap.NavGroup = function(config){
4336 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4339 Roo.bootstrap.NavGroup.register(this);
4343 * Fires when the active item changes
4344 * @param {Roo.bootstrap.NavGroup} this
4345 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4346 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4353 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4364 getAutoCreate : function()
4366 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4372 if (Roo.bootstrap.version == 4) {
4373 if (['tabs','pills'].indexOf(this.type) != -1) {
4374 cfg.cls += ' nav-' + this.type;
4376 cfg.cls += ' navbar-nav';
4379 if (['tabs','pills'].indexOf(this.type) != -1) {
4380 cfg.cls += ' nav-' + this.type
4382 if (this.type !== 'nav') {
4383 Roo.log('nav type must be nav/tabs/pills')
4385 cfg.cls += ' navbar-nav'
4389 if (this.parent() && this.parent().sidebar) {
4392 cls: 'dashboard-menu sidebar-menu'
4398 if (this.form === true) {
4401 cls: 'navbar-form form-inline'
4404 if (this.align === 'right') {
4405 cfg.cls += ' navbar-right ml-md-auto';
4407 cfg.cls += ' navbar-left';
4411 if (this.align === 'right') {
4412 cfg.cls += ' navbar-right ml-md-auto';
4414 cfg.cls += ' mr-auto';
4418 cfg.cls += ' navbar-inverse';
4426 * sets the active Navigation item
4427 * @param {Roo.bootstrap.NavItem} the new current navitem
4429 setActiveItem : function(item)
4432 Roo.each(this.navItems, function(v){
4437 v.setActive(false, true);
4444 item.setActive(true, true);
4445 this.fireEvent('changed', this, item, prev);
4450 * gets the active Navigation item
4451 * @return {Roo.bootstrap.NavItem} the current navitem
4453 getActive : function()
4457 Roo.each(this.navItems, function(v){
4468 indexOfNav : function()
4472 Roo.each(this.navItems, function(v,i){
4483 * adds a Navigation item
4484 * @param {Roo.bootstrap.NavItem} the navitem to add
4486 addItem : function(cfg)
4488 if (this.form && Roo.bootstrap.version == 4) {
4491 var cn = new Roo.bootstrap.NavItem(cfg);
4493 cn.parentId = this.id;
4494 cn.onRender(this.el, null);
4498 * register a Navigation item
4499 * @param {Roo.bootstrap.NavItem} the navitem to add
4501 register : function(item)
4503 this.navItems.push( item);
4504 item.navId = this.navId;
4509 * clear all the Navigation item
4512 clearAll : function()
4515 this.el.dom.innerHTML = '';
4518 getNavItem: function(tabId)
4521 Roo.each(this.navItems, function(e) {
4522 if (e.tabId == tabId) {
4532 setActiveNext : function()
4534 var i = this.indexOfNav(this.getActive());
4535 if (i > this.navItems.length) {
4538 this.setActiveItem(this.navItems[i+1]);
4540 setActivePrev : function()
4542 var i = this.indexOfNav(this.getActive());
4546 this.setActiveItem(this.navItems[i-1]);
4548 clearWasActive : function(except) {
4549 Roo.each(this.navItems, function(e) {
4550 if (e.tabId != except.tabId && e.was_active) {
4551 e.was_active = false;
4558 getWasActive : function ()
4561 Roo.each(this.navItems, function(e) {
4576 Roo.apply(Roo.bootstrap.NavGroup, {
4580 * register a Navigation Group
4581 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4583 register : function(navgrp)
4585 this.groups[navgrp.navId] = navgrp;
4589 * fetch a Navigation Group based on the navigation ID
4590 * @param {string} the navgroup to add
4591 * @returns {Roo.bootstrap.NavGroup} the navgroup
4593 get: function(navId) {
4594 if (typeof(this.groups[navId]) == 'undefined') {
4596 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4598 return this.groups[navId] ;
4613 * @class Roo.bootstrap.NavItem
4614 * @extends Roo.bootstrap.Component
4615 * Bootstrap Navbar.NavItem class
4616 * @cfg {String} href link to
4617 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4619 * @cfg {String} html content of button
4620 * @cfg {String} badge text inside badge
4621 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4622 * @cfg {String} glyphicon DEPRICATED - use fa
4623 * @cfg {String} icon DEPRICATED - use fa
4624 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4625 * @cfg {Boolean} active Is item active
4626 * @cfg {Boolean} disabled Is item disabled
4628 * @cfg {Boolean} preventDefault (true | false) default false
4629 * @cfg {String} tabId the tab that this item activates.
4630 * @cfg {String} tagtype (a|span) render as a href or span?
4631 * @cfg {Boolean} animateRef (true|false) link to element default false
4634 * Create a new Navbar Item
4635 * @param {Object} config The config object
4637 Roo.bootstrap.NavItem = function(config){
4638 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4643 * The raw click event for the entire grid.
4644 * @param {Roo.EventObject} e
4649 * Fires when the active item active state changes
4650 * @param {Roo.bootstrap.NavItem} this
4651 * @param {boolean} state the new state
4657 * Fires when scroll to element
4658 * @param {Roo.bootstrap.NavItem} this
4659 * @param {Object} options
4660 * @param {Roo.EventObject} e
4668 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4677 preventDefault : false,
4685 button_outline : false,
4689 getAutoCreate : function(){
4697 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4699 if (this.disabled) {
4700 cfg.cls += ' disabled';
4704 if (this.button_weight.length) {
4705 cfg.tag = this.href ? 'a' : 'button';
4706 cfg.html = this.html || '';
4707 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4709 cfg.href = this.href;
4712 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4715 // menu .. should add dropdown-menu class - so no need for carat..
4717 if (this.badge !== '') {
4719 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4724 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4728 href : this.href || "#",
4729 html: this.html || ''
4732 if (this.tagtype == 'a') {
4733 cfg.cn[0].cls = 'nav-link';
4736 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4739 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4741 if(this.glyphicon) {
4742 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4747 cfg.cn[0].html += " <span class='caret'></span>";
4751 if (this.badge !== '') {
4753 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4761 onRender : function(ct, position)
4763 // Roo.log("Call onRender: " + this.xtype);
4764 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4768 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4769 this.navLink = this.el.select('.nav-link',true).first();
4774 initEvents: function()
4776 if (typeof (this.menu) != 'undefined') {
4777 this.menu.parentType = this.xtype;
4778 this.menu.triggerEl = this.el;
4779 this.menu = this.addxtype(Roo.apply({}, this.menu));
4782 this.el.select('a',true).on('click', this.onClick, this);
4784 if(this.tagtype == 'span'){
4785 this.el.select('span',true).on('click', this.onClick, this);
4788 // at this point parent should be available..
4789 this.parent().register(this);
4792 onClick : function(e)
4794 if (e.getTarget('.dropdown-menu-item')) {
4795 // did you click on a menu itemm.... - then don't trigger onclick..
4800 this.preventDefault ||
4803 Roo.log("NavItem - prevent Default?");
4807 if (this.disabled) {
4811 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4812 if (tg && tg.transition) {
4813 Roo.log("waiting for the transitionend");
4819 //Roo.log("fire event clicked");
4820 if(this.fireEvent('click', this, e) === false){
4824 if(this.tagtype == 'span'){
4828 //Roo.log(this.href);
4829 var ael = this.el.select('a',true).first();
4832 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4833 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4834 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4835 return; // ignore... - it's a 'hash' to another page.
4837 Roo.log("NavItem - prevent Default?");
4839 this.scrollToElement(e);
4843 var p = this.parent();
4845 if (['tabs','pills'].indexOf(p.type)!==-1) {
4846 if (typeof(p.setActiveItem) !== 'undefined') {
4847 p.setActiveItem(this);
4851 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4852 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4853 // remove the collapsed menu expand...
4854 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4858 isActive: function () {
4861 setActive : function(state, fire, is_was_active)
4863 if (this.active && !state && this.navId) {
4864 this.was_active = true;
4865 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4867 nv.clearWasActive(this);
4871 this.active = state;
4874 this.el.removeClass('active');
4875 this.navLink ? this.navLink.removeClass('active') : false;
4876 } else if (!this.el.hasClass('active')) {
4878 this.el.addClass('active');
4879 if (Roo.bootstrap.version == 4 && this.navLink ) {
4880 this.navLink.addClass('active');
4885 this.fireEvent('changed', this, state);
4888 // show a panel if it's registered and related..
4890 if (!this.navId || !this.tabId || !state || is_was_active) {
4894 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4898 var pan = tg.getPanelByName(this.tabId);
4902 // if we can not flip to new panel - go back to old nav highlight..
4903 if (false == tg.showPanel(pan)) {
4904 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4906 var onav = nv.getWasActive();
4908 onav.setActive(true, false, true);
4917 // this should not be here...
4918 setDisabled : function(state)
4920 this.disabled = state;
4922 this.el.removeClass('disabled');
4923 } else if (!this.el.hasClass('disabled')) {
4924 this.el.addClass('disabled');
4930 * Fetch the element to display the tooltip on.
4931 * @return {Roo.Element} defaults to this.el
4933 tooltipEl : function()
4935 return this.el.select('' + this.tagtype + '', true).first();
4938 scrollToElement : function(e)
4940 var c = document.body;
4943 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4945 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4946 c = document.documentElement;
4949 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4955 var o = target.calcOffsetsTo(c);
4962 this.fireEvent('scrollto', this, options, e);
4964 Roo.get(c).scrollTo('top', options.value, true);
4977 * <span> icon </span>
4978 * <span> text </span>
4979 * <span>badge </span>
4983 * @class Roo.bootstrap.NavSidebarItem
4984 * @extends Roo.bootstrap.NavItem
4985 * Bootstrap Navbar.NavSidebarItem class
4986 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4987 * {Boolean} open is the menu open
4988 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4989 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4990 * {String} buttonSize (sm|md|lg)the extra classes for the button
4991 * {Boolean} showArrow show arrow next to the text (default true)
4993 * Create a new Navbar Button
4994 * @param {Object} config The config object
4996 Roo.bootstrap.NavSidebarItem = function(config){
4997 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5002 * The raw click event for the entire grid.
5003 * @param {Roo.EventObject} e
5008 * Fires when the active item active state changes
5009 * @param {Roo.bootstrap.NavSidebarItem} this
5010 * @param {boolean} state the new state
5018 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5020 badgeWeight : 'default',
5026 buttonWeight : 'default',
5032 getAutoCreate : function(){
5037 href : this.href || '#',
5043 if(this.buttonView){
5046 href : this.href || '#',
5047 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5060 cfg.cls += ' active';
5063 if (this.disabled) {
5064 cfg.cls += ' disabled';
5067 cfg.cls += ' open x-open';
5070 if (this.glyphicon || this.icon) {
5071 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5072 a.cn.push({ tag : 'i', cls : c }) ;
5075 if(!this.buttonView){
5078 html : this.html || ''
5085 if (this.badge !== '') {
5086 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5092 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5095 a.cls += ' dropdown-toggle treeview' ;
5101 initEvents : function()
5103 if (typeof (this.menu) != 'undefined') {
5104 this.menu.parentType = this.xtype;
5105 this.menu.triggerEl = this.el;
5106 this.menu = this.addxtype(Roo.apply({}, this.menu));
5109 this.el.on('click', this.onClick, this);
5111 if(this.badge !== ''){
5112 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5117 onClick : function(e)
5124 if(this.preventDefault){
5128 this.fireEvent('click', this);
5131 disable : function()
5133 this.setDisabled(true);
5138 this.setDisabled(false);
5141 setDisabled : function(state)
5143 if(this.disabled == state){
5147 this.disabled = state;
5150 this.el.addClass('disabled');
5154 this.el.removeClass('disabled');
5159 setActive : function(state)
5161 if(this.active == state){
5165 this.active = state;
5168 this.el.addClass('active');
5172 this.el.removeClass('active');
5177 isActive: function ()
5182 setBadge : function(str)
5188 this.badgeEl.dom.innerHTML = str;
5205 * @class Roo.bootstrap.Row
5206 * @extends Roo.bootstrap.Component
5207 * Bootstrap Row class (contains columns...)
5211 * @param {Object} config The config object
5214 Roo.bootstrap.Row = function(config){
5215 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5218 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5220 getAutoCreate : function(){
5239 * @class Roo.bootstrap.Element
5240 * @extends Roo.bootstrap.Component
5241 * Bootstrap Element class
5242 * @cfg {String} html contents of the element
5243 * @cfg {String} tag tag of the element
5244 * @cfg {String} cls class of the element
5245 * @cfg {Boolean} preventDefault (true|false) default false
5246 * @cfg {Boolean} clickable (true|false) default false
5249 * Create a new Element
5250 * @param {Object} config The config object
5253 Roo.bootstrap.Element = function(config){
5254 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5260 * When a element is chick
5261 * @param {Roo.bootstrap.Element} this
5262 * @param {Roo.EventObject} e
5268 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5273 preventDefault: false,
5276 getAutoCreate : function(){
5280 // cls: this.cls, double assign in parent class Component.js :: onRender
5287 initEvents: function()
5289 Roo.bootstrap.Element.superclass.initEvents.call(this);
5292 this.el.on('click', this.onClick, this);
5297 onClick : function(e)
5299 if(this.preventDefault){
5303 this.fireEvent('click', this, e);
5306 getValue : function()
5308 return this.el.dom.innerHTML;
5311 setValue : function(value)
5313 this.el.dom.innerHTML = value;
5328 * @class Roo.bootstrap.Pagination
5329 * @extends Roo.bootstrap.Component
5330 * Bootstrap Pagination class
5331 * @cfg {String} size xs | sm | md | lg
5332 * @cfg {Boolean} inverse false | true
5335 * Create a new Pagination
5336 * @param {Object} config The config object
5339 Roo.bootstrap.Pagination = function(config){
5340 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5343 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5349 getAutoCreate : function(){
5355 cfg.cls += ' inverse';
5361 cfg.cls += " " + this.cls;
5379 * @class Roo.bootstrap.PaginationItem
5380 * @extends Roo.bootstrap.Component
5381 * Bootstrap PaginationItem class
5382 * @cfg {String} html text
5383 * @cfg {String} href the link
5384 * @cfg {Boolean} preventDefault (true | false) default true
5385 * @cfg {Boolean} active (true | false) default false
5386 * @cfg {Boolean} disabled default false
5390 * Create a new PaginationItem
5391 * @param {Object} config The config object
5395 Roo.bootstrap.PaginationItem = function(config){
5396 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5401 * The raw click event for the entire grid.
5402 * @param {Roo.EventObject} e
5408 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5412 preventDefault: true,
5417 getAutoCreate : function(){
5423 href : this.href ? this.href : '#',
5424 html : this.html ? this.html : ''
5434 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5438 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5444 initEvents: function() {
5446 this.el.on('click', this.onClick, this);
5449 onClick : function(e)
5451 Roo.log('PaginationItem on click ');
5452 if(this.preventDefault){
5460 this.fireEvent('click', this, e);
5476 * @class Roo.bootstrap.Slider
5477 * @extends Roo.bootstrap.Component
5478 * Bootstrap Slider class
5481 * Create a new Slider
5482 * @param {Object} config The config object
5485 Roo.bootstrap.Slider = function(config){
5486 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5489 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5491 getAutoCreate : function(){
5495 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5499 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5511 * Ext JS Library 1.1.1
5512 * Copyright(c) 2006-2007, Ext JS, LLC.
5514 * Originally Released Under LGPL - original licence link has changed is not relivant.
5517 * <script type="text/javascript">
5522 * @class Roo.grid.ColumnModel
5523 * @extends Roo.util.Observable
5524 * This is the default implementation of a ColumnModel used by the Grid. It defines
5525 * the columns in the grid.
5528 var colModel = new Roo.grid.ColumnModel([
5529 {header: "Ticker", width: 60, sortable: true, locked: true},
5530 {header: "Company Name", width: 150, sortable: true},
5531 {header: "Market Cap.", width: 100, sortable: true},
5532 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5533 {header: "Employees", width: 100, sortable: true, resizable: false}
5538 * The config options listed for this class are options which may appear in each
5539 * individual column definition.
5540 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5542 * @param {Object} config An Array of column config objects. See this class's
5543 * config objects for details.
5545 Roo.grid.ColumnModel = function(config){
5547 * The config passed into the constructor
5549 this.config = config;
5552 // if no id, create one
5553 // if the column does not have a dataIndex mapping,
5554 // map it to the order it is in the config
5555 for(var i = 0, len = config.length; i < len; i++){
5557 if(typeof c.dataIndex == "undefined"){
5560 if(typeof c.renderer == "string"){
5561 c.renderer = Roo.util.Format[c.renderer];
5563 if(typeof c.id == "undefined"){
5566 if(c.editor && c.editor.xtype){
5567 c.editor = Roo.factory(c.editor, Roo.grid);
5569 if(c.editor && c.editor.isFormField){
5570 c.editor = new Roo.grid.GridEditor(c.editor);
5572 this.lookup[c.id] = c;
5576 * The width of columns which have no width specified (defaults to 100)
5579 this.defaultWidth = 100;
5582 * Default sortable of columns which have no sortable specified (defaults to false)
5585 this.defaultSortable = false;
5589 * @event widthchange
5590 * Fires when the width of a column changes.
5591 * @param {ColumnModel} this
5592 * @param {Number} columnIndex The column index
5593 * @param {Number} newWidth The new width
5595 "widthchange": true,
5597 * @event headerchange
5598 * Fires when the text of a header changes.
5599 * @param {ColumnModel} this
5600 * @param {Number} columnIndex The column index
5601 * @param {Number} newText The new header text
5603 "headerchange": true,
5605 * @event hiddenchange
5606 * Fires when a column is hidden or "unhidden".
5607 * @param {ColumnModel} this
5608 * @param {Number} columnIndex The column index
5609 * @param {Boolean} hidden true if hidden, false otherwise
5611 "hiddenchange": true,
5613 * @event columnmoved
5614 * Fires when a column is moved.
5615 * @param {ColumnModel} this
5616 * @param {Number} oldIndex
5617 * @param {Number} newIndex
5619 "columnmoved" : true,
5621 * @event columlockchange
5622 * Fires when a column's locked state is changed
5623 * @param {ColumnModel} this
5624 * @param {Number} colIndex
5625 * @param {Boolean} locked true if locked
5627 "columnlockchange" : true
5629 Roo.grid.ColumnModel.superclass.constructor.call(this);
5631 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5633 * @cfg {String} header The header text to display in the Grid view.
5636 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5637 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5638 * specified, the column's index is used as an index into the Record's data Array.
5641 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5642 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5645 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5646 * Defaults to the value of the {@link #defaultSortable} property.
5647 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5650 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5653 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5656 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5659 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5662 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5663 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5664 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5665 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5668 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5671 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5674 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5677 * @cfg {String} cursor (Optional)
5680 * @cfg {String} tooltip (Optional)
5683 * @cfg {Number} xs (Optional)
5686 * @cfg {Number} sm (Optional)
5689 * @cfg {Number} md (Optional)
5692 * @cfg {Number} lg (Optional)
5695 * Returns the id of the column at the specified index.
5696 * @param {Number} index The column index
5697 * @return {String} the id
5699 getColumnId : function(index){
5700 return this.config[index].id;
5704 * Returns the column for a specified id.
5705 * @param {String} id The column id
5706 * @return {Object} the column
5708 getColumnById : function(id){
5709 return this.lookup[id];
5714 * Returns the column for a specified dataIndex.
5715 * @param {String} dataIndex The column dataIndex
5716 * @return {Object|Boolean} the column or false if not found
5718 getColumnByDataIndex: function(dataIndex){
5719 var index = this.findColumnIndex(dataIndex);
5720 return index > -1 ? this.config[index] : false;
5724 * Returns the index for a specified column id.
5725 * @param {String} id The column id
5726 * @return {Number} the index, or -1 if not found
5728 getIndexById : function(id){
5729 for(var i = 0, len = this.config.length; i < len; i++){
5730 if(this.config[i].id == id){
5738 * Returns the index for a specified column dataIndex.
5739 * @param {String} dataIndex The column dataIndex
5740 * @return {Number} the index, or -1 if not found
5743 findColumnIndex : function(dataIndex){
5744 for(var i = 0, len = this.config.length; i < len; i++){
5745 if(this.config[i].dataIndex == dataIndex){
5753 moveColumn : function(oldIndex, newIndex){
5754 var c = this.config[oldIndex];
5755 this.config.splice(oldIndex, 1);
5756 this.config.splice(newIndex, 0, c);
5757 this.dataMap = null;
5758 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5761 isLocked : function(colIndex){
5762 return this.config[colIndex].locked === true;
5765 setLocked : function(colIndex, value, suppressEvent){
5766 if(this.isLocked(colIndex) == value){
5769 this.config[colIndex].locked = value;
5771 this.fireEvent("columnlockchange", this, colIndex, value);
5775 getTotalLockedWidth : function(){
5777 for(var i = 0; i < this.config.length; i++){
5778 if(this.isLocked(i) && !this.isHidden(i)){
5779 this.totalWidth += this.getColumnWidth(i);
5785 getLockedCount : function(){
5786 for(var i = 0, len = this.config.length; i < len; i++){
5787 if(!this.isLocked(i)){
5792 return this.config.length;
5796 * Returns the number of columns.
5799 getColumnCount : function(visibleOnly){
5800 if(visibleOnly === true){
5802 for(var i = 0, len = this.config.length; i < len; i++){
5803 if(!this.isHidden(i)){
5809 return this.config.length;
5813 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5814 * @param {Function} fn
5815 * @param {Object} scope (optional)
5816 * @return {Array} result
5818 getColumnsBy : function(fn, scope){
5820 for(var i = 0, len = this.config.length; i < len; i++){
5821 var c = this.config[i];
5822 if(fn.call(scope||this, c, i) === true){
5830 * Returns true if the specified column is sortable.
5831 * @param {Number} col The column index
5834 isSortable : function(col){
5835 if(typeof this.config[col].sortable == "undefined"){
5836 return this.defaultSortable;
5838 return this.config[col].sortable;
5842 * Returns the rendering (formatting) function defined for the column.
5843 * @param {Number} col The column index.
5844 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5846 getRenderer : function(col){
5847 if(!this.config[col].renderer){
5848 return Roo.grid.ColumnModel.defaultRenderer;
5850 return this.config[col].renderer;
5854 * Sets the rendering (formatting) function for a column.
5855 * @param {Number} col The column index
5856 * @param {Function} fn The function to use to process the cell's raw data
5857 * to return HTML markup for the grid view. The render function is called with
5858 * the following parameters:<ul>
5859 * <li>Data value.</li>
5860 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5861 * <li>css A CSS style string to apply to the table cell.</li>
5862 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5863 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5864 * <li>Row index</li>
5865 * <li>Column index</li>
5866 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5868 setRenderer : function(col, fn){
5869 this.config[col].renderer = fn;
5873 * Returns the width for the specified column.
5874 * @param {Number} col The column index
5877 getColumnWidth : function(col){
5878 return this.config[col].width * 1 || this.defaultWidth;
5882 * Sets the width for a column.
5883 * @param {Number} col The column index
5884 * @param {Number} width The new width
5886 setColumnWidth : function(col, width, suppressEvent){
5887 this.config[col].width = width;
5888 this.totalWidth = null;
5890 this.fireEvent("widthchange", this, col, width);
5895 * Returns the total width of all columns.
5896 * @param {Boolean} includeHidden True to include hidden column widths
5899 getTotalWidth : function(includeHidden){
5900 if(!this.totalWidth){
5901 this.totalWidth = 0;
5902 for(var i = 0, len = this.config.length; i < len; i++){
5903 if(includeHidden || !this.isHidden(i)){
5904 this.totalWidth += this.getColumnWidth(i);
5908 return this.totalWidth;
5912 * Returns the header for the specified column.
5913 * @param {Number} col The column index
5916 getColumnHeader : function(col){
5917 return this.config[col].header;
5921 * Sets the header for a column.
5922 * @param {Number} col The column index
5923 * @param {String} header The new header
5925 setColumnHeader : function(col, header){
5926 this.config[col].header = header;
5927 this.fireEvent("headerchange", this, col, header);
5931 * Returns the tooltip for the specified column.
5932 * @param {Number} col The column index
5935 getColumnTooltip : function(col){
5936 return this.config[col].tooltip;
5939 * Sets the tooltip for a column.
5940 * @param {Number} col The column index
5941 * @param {String} tooltip The new tooltip
5943 setColumnTooltip : function(col, tooltip){
5944 this.config[col].tooltip = tooltip;
5948 * Returns the dataIndex for the specified column.
5949 * @param {Number} col The column index
5952 getDataIndex : function(col){
5953 return this.config[col].dataIndex;
5957 * Sets the dataIndex for a column.
5958 * @param {Number} col The column index
5959 * @param {Number} dataIndex The new dataIndex
5961 setDataIndex : function(col, dataIndex){
5962 this.config[col].dataIndex = dataIndex;
5968 * Returns true if the cell is editable.
5969 * @param {Number} colIndex The column index
5970 * @param {Number} rowIndex The row index - this is nto actually used..?
5973 isCellEditable : function(colIndex, rowIndex){
5974 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5978 * Returns the editor defined for the cell/column.
5979 * return false or null to disable editing.
5980 * @param {Number} colIndex The column index
5981 * @param {Number} rowIndex The row index
5984 getCellEditor : function(colIndex, rowIndex){
5985 return this.config[colIndex].editor;
5989 * Sets if a column is editable.
5990 * @param {Number} col The column index
5991 * @param {Boolean} editable True if the column is editable
5993 setEditable : function(col, editable){
5994 this.config[col].editable = editable;
5999 * Returns true if the column is hidden.
6000 * @param {Number} colIndex The column index
6003 isHidden : function(colIndex){
6004 return this.config[colIndex].hidden;
6009 * Returns true if the column width cannot be changed
6011 isFixed : function(colIndex){
6012 return this.config[colIndex].fixed;
6016 * Returns true if the column can be resized
6019 isResizable : function(colIndex){
6020 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6023 * Sets if a column is hidden.
6024 * @param {Number} colIndex The column index
6025 * @param {Boolean} hidden True if the column is hidden
6027 setHidden : function(colIndex, hidden){
6028 this.config[colIndex].hidden = hidden;
6029 this.totalWidth = null;
6030 this.fireEvent("hiddenchange", this, colIndex, hidden);
6034 * Sets the editor for a column.
6035 * @param {Number} col The column index
6036 * @param {Object} editor The editor object
6038 setEditor : function(col, editor){
6039 this.config[col].editor = editor;
6043 Roo.grid.ColumnModel.defaultRenderer = function(value)
6045 if(typeof value == "object") {
6048 if(typeof value == "string" && value.length < 1){
6052 return String.format("{0}", value);
6055 // Alias for backwards compatibility
6056 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6059 * Ext JS Library 1.1.1
6060 * Copyright(c) 2006-2007, Ext JS, LLC.
6062 * Originally Released Under LGPL - original licence link has changed is not relivant.
6065 * <script type="text/javascript">
6069 * @class Roo.LoadMask
6070 * A simple utility class for generically masking elements while loading data. If the element being masked has
6071 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6072 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6073 * element's UpdateManager load indicator and will be destroyed after the initial load.
6075 * Create a new LoadMask
6076 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6077 * @param {Object} config The config object
6079 Roo.LoadMask = function(el, config){
6080 this.el = Roo.get(el);
6081 Roo.apply(this, config);
6083 this.store.on('beforeload', this.onBeforeLoad, this);
6084 this.store.on('load', this.onLoad, this);
6085 this.store.on('loadexception', this.onLoadException, this);
6086 this.removeMask = false;
6088 var um = this.el.getUpdateManager();
6089 um.showLoadIndicator = false; // disable the default indicator
6090 um.on('beforeupdate', this.onBeforeLoad, this);
6091 um.on('update', this.onLoad, this);
6092 um.on('failure', this.onLoad, this);
6093 this.removeMask = true;
6097 Roo.LoadMask.prototype = {
6099 * @cfg {Boolean} removeMask
6100 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6101 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6105 * The text to display in a centered loading message box (defaults to 'Loading...')
6109 * @cfg {String} msgCls
6110 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6112 msgCls : 'x-mask-loading',
6115 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6121 * Disables the mask to prevent it from being displayed
6123 disable : function(){
6124 this.disabled = true;
6128 * Enables the mask so that it can be displayed
6130 enable : function(){
6131 this.disabled = false;
6134 onLoadException : function()
6138 if (typeof(arguments[3]) != 'undefined') {
6139 Roo.MessageBox.alert("Error loading",arguments[3]);
6143 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6144 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6151 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6156 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6160 onBeforeLoad : function(){
6162 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6167 destroy : function(){
6169 this.store.un('beforeload', this.onBeforeLoad, this);
6170 this.store.un('load', this.onLoad, this);
6171 this.store.un('loadexception', this.onLoadException, this);
6173 var um = this.el.getUpdateManager();
6174 um.un('beforeupdate', this.onBeforeLoad, this);
6175 um.un('update', this.onLoad, this);
6176 um.un('failure', this.onLoad, this);
6187 * @class Roo.bootstrap.Table
6188 * @extends Roo.bootstrap.Component
6189 * Bootstrap Table class
6190 * @cfg {String} cls table class
6191 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6192 * @cfg {String} bgcolor Specifies the background color for a table
6193 * @cfg {Number} border Specifies whether the table cells should have borders or not
6194 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6195 * @cfg {Number} cellspacing Specifies the space between cells
6196 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6197 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6198 * @cfg {String} sortable Specifies that the table should be sortable
6199 * @cfg {String} summary Specifies a summary of the content of a table
6200 * @cfg {Number} width Specifies the width of a table
6201 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6203 * @cfg {boolean} striped Should the rows be alternative striped
6204 * @cfg {boolean} bordered Add borders to the table
6205 * @cfg {boolean} hover Add hover highlighting
6206 * @cfg {boolean} condensed Format condensed
6207 * @cfg {boolean} responsive Format condensed
6208 * @cfg {Boolean} loadMask (true|false) default false
6209 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6210 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6211 * @cfg {Boolean} rowSelection (true|false) default false
6212 * @cfg {Boolean} cellSelection (true|false) default false
6213 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6214 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6215 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6216 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6220 * Create a new Table
6221 * @param {Object} config The config object
6224 Roo.bootstrap.Table = function(config){
6225 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6230 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6231 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6232 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6233 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6235 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6237 this.sm.grid = this;
6238 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6239 this.sm = this.selModel;
6240 this.sm.xmodule = this.xmodule || false;
6243 if (this.cm && typeof(this.cm.config) == 'undefined') {
6244 this.colModel = new Roo.grid.ColumnModel(this.cm);
6245 this.cm = this.colModel;
6246 this.cm.xmodule = this.xmodule || false;
6249 this.store= Roo.factory(this.store, Roo.data);
6250 this.ds = this.store;
6251 this.ds.xmodule = this.xmodule || false;
6254 if (this.footer && this.store) {
6255 this.footer.dataSource = this.ds;
6256 this.footer = Roo.factory(this.footer);
6263 * Fires when a cell is clicked
6264 * @param {Roo.bootstrap.Table} this
6265 * @param {Roo.Element} el
6266 * @param {Number} rowIndex
6267 * @param {Number} columnIndex
6268 * @param {Roo.EventObject} e
6272 * @event celldblclick
6273 * Fires when a cell is double clicked
6274 * @param {Roo.bootstrap.Table} this
6275 * @param {Roo.Element} el
6276 * @param {Number} rowIndex
6277 * @param {Number} columnIndex
6278 * @param {Roo.EventObject} e
6280 "celldblclick" : true,
6283 * Fires when a row is clicked
6284 * @param {Roo.bootstrap.Table} this
6285 * @param {Roo.Element} el
6286 * @param {Number} rowIndex
6287 * @param {Roo.EventObject} e
6291 * @event rowdblclick
6292 * Fires when a row is double clicked
6293 * @param {Roo.bootstrap.Table} this
6294 * @param {Roo.Element} el
6295 * @param {Number} rowIndex
6296 * @param {Roo.EventObject} e
6298 "rowdblclick" : true,
6301 * Fires when a mouseover occur
6302 * @param {Roo.bootstrap.Table} this
6303 * @param {Roo.Element} el
6304 * @param {Number} rowIndex
6305 * @param {Number} columnIndex
6306 * @param {Roo.EventObject} e
6311 * Fires when a mouseout occur
6312 * @param {Roo.bootstrap.Table} this
6313 * @param {Roo.Element} el
6314 * @param {Number} rowIndex
6315 * @param {Number} columnIndex
6316 * @param {Roo.EventObject} e
6321 * Fires when a row is rendered, so you can change add a style to it.
6322 * @param {Roo.bootstrap.Table} this
6323 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6327 * @event rowsrendered
6328 * Fires when all the rows have been rendered
6329 * @param {Roo.bootstrap.Table} this
6331 'rowsrendered' : true,
6333 * @event contextmenu
6334 * The raw contextmenu event for the entire grid.
6335 * @param {Roo.EventObject} e
6337 "contextmenu" : true,
6339 * @event rowcontextmenu
6340 * Fires when a row is right clicked
6341 * @param {Roo.bootstrap.Table} this
6342 * @param {Number} rowIndex
6343 * @param {Roo.EventObject} e
6345 "rowcontextmenu" : true,
6347 * @event cellcontextmenu
6348 * Fires when a cell is right clicked
6349 * @param {Roo.bootstrap.Table} this
6350 * @param {Number} rowIndex
6351 * @param {Number} cellIndex
6352 * @param {Roo.EventObject} e
6354 "cellcontextmenu" : true,
6356 * @event headercontextmenu
6357 * Fires when a header is right clicked
6358 * @param {Roo.bootstrap.Table} this
6359 * @param {Number} columnIndex
6360 * @param {Roo.EventObject} e
6362 "headercontextmenu" : true
6366 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6392 rowSelection : false,
6393 cellSelection : false,
6396 // Roo.Element - the tbody
6398 // Roo.Element - thead element
6401 container: false, // used by gridpanel...
6407 auto_hide_footer : false,
6409 getAutoCreate : function()
6411 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6418 if (this.scrollBody) {
6419 cfg.cls += ' table-body-fixed';
6422 cfg.cls += ' table-striped';
6426 cfg.cls += ' table-hover';
6428 if (this.bordered) {
6429 cfg.cls += ' table-bordered';
6431 if (this.condensed) {
6432 cfg.cls += ' table-condensed';
6434 if (this.responsive) {
6435 cfg.cls += ' table-responsive';
6439 cfg.cls+= ' ' +this.cls;
6442 // this lot should be simplifed...
6455 ].forEach(function(k) {
6463 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6466 if(this.store || this.cm){
6467 if(this.headerShow){
6468 cfg.cn.push(this.renderHeader());
6471 cfg.cn.push(this.renderBody());
6473 if(this.footerShow){
6474 cfg.cn.push(this.renderFooter());
6476 // where does this come from?
6477 //cfg.cls+= ' TableGrid';
6480 return { cn : [ cfg ] };
6483 initEvents : function()
6485 if(!this.store || !this.cm){
6488 if (this.selModel) {
6489 this.selModel.initEvents();
6493 //Roo.log('initEvents with ds!!!!');
6495 this.mainBody = this.el.select('tbody', true).first();
6496 this.mainHead = this.el.select('thead', true).first();
6497 this.mainFoot = this.el.select('tfoot', true).first();
6503 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6504 e.on('click', _this.sort, _this);
6507 this.mainBody.on("click", this.onClick, this);
6508 this.mainBody.on("dblclick", this.onDblClick, this);
6510 // why is this done????? = it breaks dialogs??
6511 //this.parent().el.setStyle('position', 'relative');
6515 this.footer.parentId = this.id;
6516 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6519 this.el.select('tfoot tr td').first().addClass('hide');
6524 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6527 this.store.on('load', this.onLoad, this);
6528 this.store.on('beforeload', this.onBeforeLoad, this);
6529 this.store.on('update', this.onUpdate, this);
6530 this.store.on('add', this.onAdd, this);
6531 this.store.on("clear", this.clear, this);
6533 this.el.on("contextmenu", this.onContextMenu, this);
6535 this.mainBody.on('scroll', this.onBodyScroll, this);
6537 this.cm.on("headerchange", this.onHeaderChange, this);
6539 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6543 onContextMenu : function(e, t)
6545 this.processEvent("contextmenu", e);
6548 processEvent : function(name, e)
6550 if (name != 'touchstart' ) {
6551 this.fireEvent(name, e);
6554 var t = e.getTarget();
6556 var cell = Roo.get(t);
6562 if(cell.findParent('tfoot', false, true)){
6566 if(cell.findParent('thead', false, true)){
6568 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6569 cell = Roo.get(t).findParent('th', false, true);
6571 Roo.log("failed to find th in thead?");
6572 Roo.log(e.getTarget());
6577 var cellIndex = cell.dom.cellIndex;
6579 var ename = name == 'touchstart' ? 'click' : name;
6580 this.fireEvent("header" + ename, this, cellIndex, e);
6585 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6586 cell = Roo.get(t).findParent('td', false, true);
6588 Roo.log("failed to find th in tbody?");
6589 Roo.log(e.getTarget());
6594 var row = cell.findParent('tr', false, true);
6595 var cellIndex = cell.dom.cellIndex;
6596 var rowIndex = row.dom.rowIndex - 1;
6600 this.fireEvent("row" + name, this, rowIndex, e);
6604 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6610 onMouseover : function(e, el)
6612 var cell = Roo.get(el);
6618 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6619 cell = cell.findParent('td', false, true);
6622 var row = cell.findParent('tr', false, true);
6623 var cellIndex = cell.dom.cellIndex;
6624 var rowIndex = row.dom.rowIndex - 1; // start from 0
6626 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6630 onMouseout : function(e, el)
6632 var cell = Roo.get(el);
6638 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6639 cell = cell.findParent('td', false, true);
6642 var row = cell.findParent('tr', false, true);
6643 var cellIndex = cell.dom.cellIndex;
6644 var rowIndex = row.dom.rowIndex - 1; // start from 0
6646 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6650 onClick : function(e, el)
6652 var cell = Roo.get(el);
6654 if(!cell || (!this.cellSelection && !this.rowSelection)){
6658 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6659 cell = cell.findParent('td', false, true);
6662 if(!cell || typeof(cell) == 'undefined'){
6666 var row = cell.findParent('tr', false, true);
6668 if(!row || typeof(row) == 'undefined'){
6672 var cellIndex = cell.dom.cellIndex;
6673 var rowIndex = this.getRowIndex(row);
6675 // why??? - should these not be based on SelectionModel?
6676 if(this.cellSelection){
6677 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6680 if(this.rowSelection){
6681 this.fireEvent('rowclick', this, row, rowIndex, e);
6687 onDblClick : function(e,el)
6689 var cell = Roo.get(el);
6691 if(!cell || (!this.cellSelection && !this.rowSelection)){
6695 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6696 cell = cell.findParent('td', false, true);
6699 if(!cell || typeof(cell) == 'undefined'){
6703 var row = cell.findParent('tr', false, true);
6705 if(!row || typeof(row) == 'undefined'){
6709 var cellIndex = cell.dom.cellIndex;
6710 var rowIndex = this.getRowIndex(row);
6712 if(this.cellSelection){
6713 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6716 if(this.rowSelection){
6717 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6721 sort : function(e,el)
6723 var col = Roo.get(el);
6725 if(!col.hasClass('sortable')){
6729 var sort = col.attr('sort');
6732 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6736 this.store.sortInfo = {field : sort, direction : dir};
6739 Roo.log("calling footer first");
6740 this.footer.onClick('first');
6743 this.store.load({ params : { start : 0 } });
6747 renderHeader : function()
6755 this.totalWidth = 0;
6757 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6759 var config = cm.config[i];
6763 cls : 'x-hcol-' + i,
6765 html: cm.getColumnHeader(i)
6770 if(typeof(config.sortable) != 'undefined' && config.sortable){
6772 c.html = '<i class="glyphicon"></i>' + c.html;
6775 if(typeof(config.lgHeader) != 'undefined'){
6776 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6779 if(typeof(config.mdHeader) != 'undefined'){
6780 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6783 if(typeof(config.smHeader) != 'undefined'){
6784 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6787 if(typeof(config.xsHeader) != 'undefined'){
6788 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6795 if(typeof(config.tooltip) != 'undefined'){
6796 c.tooltip = config.tooltip;
6799 if(typeof(config.colspan) != 'undefined'){
6800 c.colspan = config.colspan;
6803 if(typeof(config.hidden) != 'undefined' && config.hidden){
6804 c.style += ' display:none;';
6807 if(typeof(config.dataIndex) != 'undefined'){
6808 c.sort = config.dataIndex;
6813 if(typeof(config.align) != 'undefined' && config.align.length){
6814 c.style += ' text-align:' + config.align + ';';
6817 if(typeof(config.width) != 'undefined'){
6818 c.style += ' width:' + config.width + 'px;';
6819 this.totalWidth += config.width;
6821 this.totalWidth += 100; // assume minimum of 100 per column?
6824 if(typeof(config.cls) != 'undefined'){
6825 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6828 ['xs','sm','md','lg'].map(function(size){
6830 if(typeof(config[size]) == 'undefined'){
6834 if (!config[size]) { // 0 = hidden
6835 c.cls += ' hidden-' + size;
6839 c.cls += ' col-' + size + '-' + config[size];
6849 renderBody : function()
6859 colspan : this.cm.getColumnCount()
6869 renderFooter : function()
6879 colspan : this.cm.getColumnCount()
6893 // Roo.log('ds onload');
6898 var ds = this.store;
6900 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6901 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6902 if (_this.store.sortInfo) {
6904 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6905 e.select('i', true).addClass(['glyphicon-arrow-up']);
6908 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6909 e.select('i', true).addClass(['glyphicon-arrow-down']);
6914 var tbody = this.mainBody;
6916 if(ds.getCount() > 0){
6917 ds.data.each(function(d,rowIndex){
6918 var row = this.renderRow(cm, ds, rowIndex);
6920 tbody.createChild(row);
6924 if(row.cellObjects.length){
6925 Roo.each(row.cellObjects, function(r){
6926 _this.renderCellObject(r);
6933 var tfoot = this.el.select('tfoot', true).first();
6935 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6937 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6939 var total = this.ds.getTotalCount();
6941 if(this.footer.pageSize < total){
6942 this.mainFoot.show();
6946 Roo.each(this.el.select('tbody td', true).elements, function(e){
6947 e.on('mouseover', _this.onMouseover, _this);
6950 Roo.each(this.el.select('tbody td', true).elements, function(e){
6951 e.on('mouseout', _this.onMouseout, _this);
6953 this.fireEvent('rowsrendered', this);
6959 onUpdate : function(ds,record)
6961 this.refreshRow(record);
6965 onRemove : function(ds, record, index, isUpdate){
6966 if(isUpdate !== true){
6967 this.fireEvent("beforerowremoved", this, index, record);
6969 var bt = this.mainBody.dom;
6971 var rows = this.el.select('tbody > tr', true).elements;
6973 if(typeof(rows[index]) != 'undefined'){
6974 bt.removeChild(rows[index].dom);
6977 // if(bt.rows[index]){
6978 // bt.removeChild(bt.rows[index]);
6981 if(isUpdate !== true){
6982 //this.stripeRows(index);
6983 //this.syncRowHeights(index, index);
6985 this.fireEvent("rowremoved", this, index, record);
6989 onAdd : function(ds, records, rowIndex)
6991 //Roo.log('on Add called');
6992 // - note this does not handle multiple adding very well..
6993 var bt = this.mainBody.dom;
6994 for (var i =0 ; i < records.length;i++) {
6995 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6996 //Roo.log(records[i]);
6997 //Roo.log(this.store.getAt(rowIndex+i));
6998 this.insertRow(this.store, rowIndex + i, false);
7005 refreshRow : function(record){
7006 var ds = this.store, index;
7007 if(typeof record == 'number'){
7009 record = ds.getAt(index);
7011 index = ds.indexOf(record);
7013 this.insertRow(ds, index, true);
7015 this.onRemove(ds, record, index+1, true);
7017 //this.syncRowHeights(index, index);
7019 this.fireEvent("rowupdated", this, index, record);
7022 insertRow : function(dm, rowIndex, isUpdate){
7025 this.fireEvent("beforerowsinserted", this, rowIndex);
7027 //var s = this.getScrollState();
7028 var row = this.renderRow(this.cm, this.store, rowIndex);
7029 // insert before rowIndex..
7030 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7034 if(row.cellObjects.length){
7035 Roo.each(row.cellObjects, function(r){
7036 _this.renderCellObject(r);
7041 this.fireEvent("rowsinserted", this, rowIndex);
7042 //this.syncRowHeights(firstRow, lastRow);
7043 //this.stripeRows(firstRow);
7050 getRowDom : function(rowIndex)
7052 var rows = this.el.select('tbody > tr', true).elements;
7054 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7057 // returns the object tree for a tr..
7060 renderRow : function(cm, ds, rowIndex)
7062 var d = ds.getAt(rowIndex);
7066 cls : 'x-row-' + rowIndex,
7070 var cellObjects = [];
7072 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7073 var config = cm.config[i];
7075 var renderer = cm.getRenderer(i);
7079 if(typeof(renderer) !== 'undefined'){
7080 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7082 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7083 // and are rendered into the cells after the row is rendered - using the id for the element.
7085 if(typeof(value) === 'object'){
7095 rowIndex : rowIndex,
7100 this.fireEvent('rowclass', this, rowcfg);
7104 cls : rowcfg.rowClass + ' x-col-' + i,
7106 html: (typeof(value) === 'object') ? '' : value
7113 if(typeof(config.colspan) != 'undefined'){
7114 td.colspan = config.colspan;
7117 if(typeof(config.hidden) != 'undefined' && config.hidden){
7118 td.style += ' display:none;';
7121 if(typeof(config.align) != 'undefined' && config.align.length){
7122 td.style += ' text-align:' + config.align + ';';
7124 if(typeof(config.valign) != 'undefined' && config.valign.length){
7125 td.style += ' vertical-align:' + config.valign + ';';
7128 if(typeof(config.width) != 'undefined'){
7129 td.style += ' width:' + config.width + 'px;';
7132 if(typeof(config.cursor) != 'undefined'){
7133 td.style += ' cursor:' + config.cursor + ';';
7136 if(typeof(config.cls) != 'undefined'){
7137 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7140 ['xs','sm','md','lg'].map(function(size){
7142 if(typeof(config[size]) == 'undefined'){
7146 if (!config[size]) { // 0 = hidden
7147 td.cls += ' hidden-' + size;
7151 td.cls += ' col-' + size + '-' + config[size];
7159 row.cellObjects = cellObjects;
7167 onBeforeLoad : function()
7176 this.el.select('tbody', true).first().dom.innerHTML = '';
7179 * Show or hide a row.
7180 * @param {Number} rowIndex to show or hide
7181 * @param {Boolean} state hide
7183 setRowVisibility : function(rowIndex, state)
7185 var bt = this.mainBody.dom;
7187 var rows = this.el.select('tbody > tr', true).elements;
7189 if(typeof(rows[rowIndex]) == 'undefined'){
7192 rows[rowIndex].dom.style.display = state ? '' : 'none';
7196 getSelectionModel : function(){
7198 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7200 return this.selModel;
7203 * Render the Roo.bootstrap object from renderder
7205 renderCellObject : function(r)
7209 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7211 var t = r.cfg.render(r.container);
7214 Roo.each(r.cfg.cn, function(c){
7216 container: t.getChildContainer(),
7219 _this.renderCellObject(child);
7224 getRowIndex : function(row)
7228 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7239 * Returns the grid's underlying element = used by panel.Grid
7240 * @return {Element} The element
7242 getGridEl : function(){
7246 * Forces a resize - used by panel.Grid
7247 * @return {Element} The element
7249 autoSize : function()
7251 //var ctr = Roo.get(this.container.dom.parentElement);
7252 var ctr = Roo.get(this.el.dom);
7254 var thd = this.getGridEl().select('thead',true).first();
7255 var tbd = this.getGridEl().select('tbody', true).first();
7256 var tfd = this.getGridEl().select('tfoot', true).first();
7258 var cw = ctr.getWidth();
7262 tbd.setSize(ctr.getWidth(),
7263 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7265 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7268 cw = Math.max(cw, this.totalWidth);
7269 this.getGridEl().select('tr',true).setWidth(cw);
7270 // resize 'expandable coloumn?
7272 return; // we doe not have a view in this design..
7275 onBodyScroll: function()
7277 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7279 this.mainHead.setStyle({
7280 'position' : 'relative',
7281 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7287 var scrollHeight = this.mainBody.dom.scrollHeight;
7289 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7291 var height = this.mainBody.getHeight();
7293 if(scrollHeight - height == scrollTop) {
7295 var total = this.ds.getTotalCount();
7297 if(this.footer.cursor + this.footer.pageSize < total){
7299 this.footer.ds.load({
7301 start : this.footer.cursor + this.footer.pageSize,
7302 limit : this.footer.pageSize
7312 onHeaderChange : function()
7314 var header = this.renderHeader();
7315 var table = this.el.select('table', true).first();
7317 this.mainHead.remove();
7318 this.mainHead = table.createChild(header, this.mainBody, false);
7321 onHiddenChange : function(colModel, colIndex, hidden)
7323 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7324 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7326 this.CSS.updateRule(thSelector, "display", "");
7327 this.CSS.updateRule(tdSelector, "display", "");
7330 this.CSS.updateRule(thSelector, "display", "none");
7331 this.CSS.updateRule(tdSelector, "display", "none");
7334 this.onHeaderChange();
7338 setColumnWidth: function(col_index, width)
7340 // width = "md-2 xs-2..."
7341 if(!this.colModel.config[col_index]) {
7345 var w = width.split(" ");
7347 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7349 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7352 for(var j = 0; j < w.length; j++) {
7358 var size_cls = w[j].split("-");
7360 if(!Number.isInteger(size_cls[1] * 1)) {
7364 if(!this.colModel.config[col_index][size_cls[0]]) {
7368 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7372 h_row[0].classList.replace(
7373 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7374 "col-"+size_cls[0]+"-"+size_cls[1]
7377 for(var i = 0; i < rows.length; i++) {
7379 var size_cls = w[j].split("-");
7381 if(!Number.isInteger(size_cls[1] * 1)) {
7385 if(!this.colModel.config[col_index][size_cls[0]]) {
7389 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7393 rows[i].classList.replace(
7394 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7395 "col-"+size_cls[0]+"-"+size_cls[1]
7399 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7414 * @class Roo.bootstrap.TableCell
7415 * @extends Roo.bootstrap.Component
7416 * Bootstrap TableCell class
7417 * @cfg {String} html cell contain text
7418 * @cfg {String} cls cell class
7419 * @cfg {String} tag cell tag (td|th) default td
7420 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7421 * @cfg {String} align Aligns the content in a cell
7422 * @cfg {String} axis Categorizes cells
7423 * @cfg {String} bgcolor Specifies the background color of a cell
7424 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7425 * @cfg {Number} colspan Specifies the number of columns a cell should span
7426 * @cfg {String} headers Specifies one or more header cells a cell is related to
7427 * @cfg {Number} height Sets the height of a cell
7428 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7429 * @cfg {Number} rowspan Sets the number of rows a cell should span
7430 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7431 * @cfg {String} valign Vertical aligns the content in a cell
7432 * @cfg {Number} width Specifies the width of a cell
7435 * Create a new TableCell
7436 * @param {Object} config The config object
7439 Roo.bootstrap.TableCell = function(config){
7440 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7443 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7463 getAutoCreate : function(){
7464 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7484 cfg.align=this.align
7490 cfg.bgcolor=this.bgcolor
7493 cfg.charoff=this.charoff
7496 cfg.colspan=this.colspan
7499 cfg.headers=this.headers
7502 cfg.height=this.height
7505 cfg.nowrap=this.nowrap
7508 cfg.rowspan=this.rowspan
7511 cfg.scope=this.scope
7514 cfg.valign=this.valign
7517 cfg.width=this.width
7536 * @class Roo.bootstrap.TableRow
7537 * @extends Roo.bootstrap.Component
7538 * Bootstrap TableRow class
7539 * @cfg {String} cls row class
7540 * @cfg {String} align Aligns the content in a table row
7541 * @cfg {String} bgcolor Specifies a background color for a table row
7542 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7543 * @cfg {String} valign Vertical aligns the content in a table row
7546 * Create a new TableRow
7547 * @param {Object} config The config object
7550 Roo.bootstrap.TableRow = function(config){
7551 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7554 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7562 getAutoCreate : function(){
7563 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7573 cfg.align = this.align;
7576 cfg.bgcolor = this.bgcolor;
7579 cfg.charoff = this.charoff;
7582 cfg.valign = this.valign;
7600 * @class Roo.bootstrap.TableBody
7601 * @extends Roo.bootstrap.Component
7602 * Bootstrap TableBody class
7603 * @cfg {String} cls element class
7604 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7605 * @cfg {String} align Aligns the content inside the element
7606 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7607 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7610 * Create a new TableBody
7611 * @param {Object} config The config object
7614 Roo.bootstrap.TableBody = function(config){
7615 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7618 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7626 getAutoCreate : function(){
7627 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7641 cfg.align = this.align;
7644 cfg.charoff = this.charoff;
7647 cfg.valign = this.valign;
7654 // initEvents : function()
7661 // this.store = Roo.factory(this.store, Roo.data);
7662 // this.store.on('load', this.onLoad, this);
7664 // this.store.load();
7668 // onLoad: function ()
7670 // this.fireEvent('load', this);
7680 * Ext JS Library 1.1.1
7681 * Copyright(c) 2006-2007, Ext JS, LLC.
7683 * Originally Released Under LGPL - original licence link has changed is not relivant.
7686 * <script type="text/javascript">
7689 // as we use this in bootstrap.
7690 Roo.namespace('Roo.form');
7692 * @class Roo.form.Action
7693 * Internal Class used to handle form actions
7695 * @param {Roo.form.BasicForm} el The form element or its id
7696 * @param {Object} config Configuration options
7701 // define the action interface
7702 Roo.form.Action = function(form, options){
7704 this.options = options || {};
7707 * Client Validation Failed
7710 Roo.form.Action.CLIENT_INVALID = 'client';
7712 * Server Validation Failed
7715 Roo.form.Action.SERVER_INVALID = 'server';
7717 * Connect to Server Failed
7720 Roo.form.Action.CONNECT_FAILURE = 'connect';
7722 * Reading Data from Server Failed
7725 Roo.form.Action.LOAD_FAILURE = 'load';
7727 Roo.form.Action.prototype = {
7729 failureType : undefined,
7730 response : undefined,
7734 run : function(options){
7739 success : function(response){
7744 handleResponse : function(response){
7748 // default connection failure
7749 failure : function(response){
7751 this.response = response;
7752 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7753 this.form.afterAction(this, false);
7756 processResponse : function(response){
7757 this.response = response;
7758 if(!response.responseText){
7761 this.result = this.handleResponse(response);
7765 // utility functions used internally
7766 getUrl : function(appendParams){
7767 var url = this.options.url || this.form.url || this.form.el.dom.action;
7769 var p = this.getParams();
7771 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7777 getMethod : function(){
7778 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7781 getParams : function(){
7782 var bp = this.form.baseParams;
7783 var p = this.options.params;
7785 if(typeof p == "object"){
7786 p = Roo.urlEncode(Roo.applyIf(p, bp));
7787 }else if(typeof p == 'string' && bp){
7788 p += '&' + Roo.urlEncode(bp);
7791 p = Roo.urlEncode(bp);
7796 createCallback : function(){
7798 success: this.success,
7799 failure: this.failure,
7801 timeout: (this.form.timeout*1000),
7802 upload: this.form.fileUpload ? this.success : undefined
7807 Roo.form.Action.Submit = function(form, options){
7808 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7811 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7814 haveProgress : false,
7815 uploadComplete : false,
7817 // uploadProgress indicator.
7818 uploadProgress : function()
7820 if (!this.form.progressUrl) {
7824 if (!this.haveProgress) {
7825 Roo.MessageBox.progress("Uploading", "Uploading");
7827 if (this.uploadComplete) {
7828 Roo.MessageBox.hide();
7832 this.haveProgress = true;
7834 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7836 var c = new Roo.data.Connection();
7838 url : this.form.progressUrl,
7843 success : function(req){
7844 //console.log(data);
7848 rdata = Roo.decode(req.responseText)
7850 Roo.log("Invalid data from server..");
7854 if (!rdata || !rdata.success) {
7856 Roo.MessageBox.alert(Roo.encode(rdata));
7859 var data = rdata.data;
7861 if (this.uploadComplete) {
7862 Roo.MessageBox.hide();
7867 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7868 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7871 this.uploadProgress.defer(2000,this);
7874 failure: function(data) {
7875 Roo.log('progress url failed ');
7886 // run get Values on the form, so it syncs any secondary forms.
7887 this.form.getValues();
7889 var o = this.options;
7890 var method = this.getMethod();
7891 var isPost = method == 'POST';
7892 if(o.clientValidation === false || this.form.isValid()){
7894 if (this.form.progressUrl) {
7895 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7896 (new Date() * 1) + '' + Math.random());
7901 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7902 form:this.form.el.dom,
7903 url:this.getUrl(!isPost),
7905 params:isPost ? this.getParams() : null,
7906 isUpload: this.form.fileUpload,
7907 formData : this.form.formData
7910 this.uploadProgress();
7912 }else if (o.clientValidation !== false){ // client validation failed
7913 this.failureType = Roo.form.Action.CLIENT_INVALID;
7914 this.form.afterAction(this, false);
7918 success : function(response)
7920 this.uploadComplete= true;
7921 if (this.haveProgress) {
7922 Roo.MessageBox.hide();
7926 var result = this.processResponse(response);
7927 if(result === true || result.success){
7928 this.form.afterAction(this, true);
7932 this.form.markInvalid(result.errors);
7933 this.failureType = Roo.form.Action.SERVER_INVALID;
7935 this.form.afterAction(this, false);
7937 failure : function(response)
7939 this.uploadComplete= true;
7940 if (this.haveProgress) {
7941 Roo.MessageBox.hide();
7944 this.response = response;
7945 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7946 this.form.afterAction(this, false);
7949 handleResponse : function(response){
7950 if(this.form.errorReader){
7951 var rs = this.form.errorReader.read(response);
7954 for(var i = 0, len = rs.records.length; i < len; i++) {
7955 var r = rs.records[i];
7959 if(errors.length < 1){
7963 success : rs.success,
7969 ret = Roo.decode(response.responseText);
7973 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7983 Roo.form.Action.Load = function(form, options){
7984 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7985 this.reader = this.form.reader;
7988 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7993 Roo.Ajax.request(Roo.apply(
7994 this.createCallback(), {
7995 method:this.getMethod(),
7996 url:this.getUrl(false),
7997 params:this.getParams()
8001 success : function(response){
8003 var result = this.processResponse(response);
8004 if(result === true || !result.success || !result.data){
8005 this.failureType = Roo.form.Action.LOAD_FAILURE;
8006 this.form.afterAction(this, false);
8009 this.form.clearInvalid();
8010 this.form.setValues(result.data);
8011 this.form.afterAction(this, true);
8014 handleResponse : function(response){
8015 if(this.form.reader){
8016 var rs = this.form.reader.read(response);
8017 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8019 success : rs.success,
8023 return Roo.decode(response.responseText);
8027 Roo.form.Action.ACTION_TYPES = {
8028 'load' : Roo.form.Action.Load,
8029 'submit' : Roo.form.Action.Submit
8038 * @class Roo.bootstrap.Form
8039 * @extends Roo.bootstrap.Component
8040 * Bootstrap Form class
8041 * @cfg {String} method GET | POST (default POST)
8042 * @cfg {String} labelAlign top | left (default top)
8043 * @cfg {String} align left | right - for navbars
8044 * @cfg {Boolean} loadMask load mask when submit (default true)
8049 * @param {Object} config The config object
8053 Roo.bootstrap.Form = function(config){
8055 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8057 Roo.bootstrap.Form.popover.apply();
8061 * @event clientvalidation
8062 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8063 * @param {Form} this
8064 * @param {Boolean} valid true if the form has passed client-side validation
8066 clientvalidation: true,
8068 * @event beforeaction
8069 * Fires before any action is performed. Return false to cancel the action.
8070 * @param {Form} this
8071 * @param {Action} action The action to be performed
8075 * @event actionfailed
8076 * Fires when an action fails.
8077 * @param {Form} this
8078 * @param {Action} action The action that failed
8080 actionfailed : true,
8082 * @event actioncomplete
8083 * Fires when an action is completed.
8084 * @param {Form} this
8085 * @param {Action} action The action that completed
8087 actioncomplete : true
8091 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8094 * @cfg {String} method
8095 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8100 * The URL to use for form actions if one isn't supplied in the action options.
8103 * @cfg {Boolean} fileUpload
8104 * Set to true if this form is a file upload.
8108 * @cfg {Object} baseParams
8109 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8113 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8117 * @cfg {Sting} align (left|right) for navbar forms
8122 activeAction : null,
8125 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8126 * element by passing it or its id or mask the form itself by passing in true.
8129 waitMsgTarget : false,
8134 * @cfg {Boolean} errorMask (true|false) default false
8139 * @cfg {Number} maskOffset Default 100
8144 * @cfg {Boolean} maskBody
8148 getAutoCreate : function(){
8152 method : this.method || 'POST',
8153 id : this.id || Roo.id(),
8156 if (this.parent().xtype.match(/^Nav/)) {
8157 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8161 if (this.labelAlign == 'left' ) {
8162 cfg.cls += ' form-horizontal';
8168 initEvents : function()
8170 this.el.on('submit', this.onSubmit, this);
8171 // this was added as random key presses on the form where triggering form submit.
8172 this.el.on('keypress', function(e) {
8173 if (e.getCharCode() != 13) {
8176 // we might need to allow it for textareas.. and some other items.
8177 // check e.getTarget().
8179 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8183 Roo.log("keypress blocked");
8191 onSubmit : function(e){
8196 * Returns true if client-side validation on the form is successful.
8199 isValid : function(){
8200 var items = this.getItems();
8204 items.each(function(f){
8210 Roo.log('invalid field: ' + f.name);
8214 if(!target && f.el.isVisible(true)){
8220 if(this.errorMask && !valid){
8221 Roo.bootstrap.Form.popover.mask(this, target);
8228 * Returns true if any fields in this form have changed since their original load.
8231 isDirty : function(){
8233 var items = this.getItems();
8234 items.each(function(f){
8244 * Performs a predefined action (submit or load) or custom actions you define on this form.
8245 * @param {String} actionName The name of the action type
8246 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8247 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8248 * accept other config options):
8250 Property Type Description
8251 ---------------- --------------- ----------------------------------------------------------------------------------
8252 url String The url for the action (defaults to the form's url)
8253 method String The form method to use (defaults to the form's method, or POST if not defined)
8254 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8255 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8256 validate the form on the client (defaults to false)
8258 * @return {BasicForm} this
8260 doAction : function(action, options){
8261 if(typeof action == 'string'){
8262 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8264 if(this.fireEvent('beforeaction', this, action) !== false){
8265 this.beforeAction(action);
8266 action.run.defer(100, action);
8272 beforeAction : function(action){
8273 var o = action.options;
8278 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8280 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8283 // not really supported yet.. ??
8285 //if(this.waitMsgTarget === true){
8286 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8287 //}else if(this.waitMsgTarget){
8288 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8289 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8291 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8297 afterAction : function(action, success){
8298 this.activeAction = null;
8299 var o = action.options;
8304 Roo.get(document.body).unmask();
8310 //if(this.waitMsgTarget === true){
8311 // this.el.unmask();
8312 //}else if(this.waitMsgTarget){
8313 // this.waitMsgTarget.unmask();
8315 // Roo.MessageBox.updateProgress(1);
8316 // Roo.MessageBox.hide();
8323 Roo.callback(o.success, o.scope, [this, action]);
8324 this.fireEvent('actioncomplete', this, action);
8328 // failure condition..
8329 // we have a scenario where updates need confirming.
8330 // eg. if a locking scenario exists..
8331 // we look for { errors : { needs_confirm : true }} in the response.
8333 (typeof(action.result) != 'undefined') &&
8334 (typeof(action.result.errors) != 'undefined') &&
8335 (typeof(action.result.errors.needs_confirm) != 'undefined')
8338 Roo.log("not supported yet");
8341 Roo.MessageBox.confirm(
8342 "Change requires confirmation",
8343 action.result.errorMsg,
8348 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8358 Roo.callback(o.failure, o.scope, [this, action]);
8359 // show an error message if no failed handler is set..
8360 if (!this.hasListener('actionfailed')) {
8361 Roo.log("need to add dialog support");
8363 Roo.MessageBox.alert("Error",
8364 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8365 action.result.errorMsg :
8366 "Saving Failed, please check your entries or try again"
8371 this.fireEvent('actionfailed', this, action);
8376 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8377 * @param {String} id The value to search for
8380 findField : function(id){
8381 var items = this.getItems();
8382 var field = items.get(id);
8384 items.each(function(f){
8385 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8392 return field || null;
8395 * Mark fields in this form invalid in bulk.
8396 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8397 * @return {BasicForm} this
8399 markInvalid : function(errors){
8400 if(errors instanceof Array){
8401 for(var i = 0, len = errors.length; i < len; i++){
8402 var fieldError = errors[i];
8403 var f = this.findField(fieldError.id);
8405 f.markInvalid(fieldError.msg);
8411 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8412 field.markInvalid(errors[id]);
8416 //Roo.each(this.childForms || [], function (f) {
8417 // f.markInvalid(errors);
8424 * Set values for fields in this form in bulk.
8425 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8426 * @return {BasicForm} this
8428 setValues : function(values){
8429 if(values instanceof Array){ // array of objects
8430 for(var i = 0, len = values.length; i < len; i++){
8432 var f = this.findField(v.id);
8434 f.setValue(v.value);
8435 if(this.trackResetOnLoad){
8436 f.originalValue = f.getValue();
8440 }else{ // object hash
8443 if(typeof values[id] != 'function' && (field = this.findField(id))){
8445 if (field.setFromData &&
8447 field.displayField &&
8448 // combos' with local stores can
8449 // be queried via setValue()
8450 // to set their value..
8451 (field.store && !field.store.isLocal)
8455 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8456 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8457 field.setFromData(sd);
8459 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8461 field.setFromData(values);
8464 field.setValue(values[id]);
8468 if(this.trackResetOnLoad){
8469 field.originalValue = field.getValue();
8475 //Roo.each(this.childForms || [], function (f) {
8476 // f.setValues(values);
8483 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8484 * they are returned as an array.
8485 * @param {Boolean} asString
8488 getValues : function(asString){
8489 //if (this.childForms) {
8490 // copy values from the child forms
8491 // Roo.each(this.childForms, function (f) {
8492 // this.setValues(f.getValues());
8498 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8499 if(asString === true){
8502 return Roo.urlDecode(fs);
8506 * Returns the fields in this form as an object with key/value pairs.
8507 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8510 getFieldValues : function(with_hidden)
8512 var items = this.getItems();
8514 items.each(function(f){
8520 var v = f.getValue();
8522 if (f.inputType =='radio') {
8523 if (typeof(ret[f.getName()]) == 'undefined') {
8524 ret[f.getName()] = ''; // empty..
8527 if (!f.el.dom.checked) {
8535 if(f.xtype == 'MoneyField'){
8536 ret[f.currencyName] = f.getCurrency();
8539 // not sure if this supported any more..
8540 if ((typeof(v) == 'object') && f.getRawValue) {
8541 v = f.getRawValue() ; // dates..
8543 // combo boxes where name != hiddenName...
8544 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8545 ret[f.name] = f.getRawValue();
8547 ret[f.getName()] = v;
8554 * Clears all invalid messages in this form.
8555 * @return {BasicForm} this
8557 clearInvalid : function(){
8558 var items = this.getItems();
8560 items.each(function(f){
8569 * @return {BasicForm} this
8572 var items = this.getItems();
8573 items.each(function(f){
8577 Roo.each(this.childForms || [], function (f) {
8585 getItems : function()
8587 var r=new Roo.util.MixedCollection(false, function(o){
8588 return o.id || (o.id = Roo.id());
8590 var iter = function(el) {
8597 Roo.each(el.items,function(e) {
8606 hideFields : function(items)
8608 Roo.each(items, function(i){
8610 var f = this.findField(i);
8621 showFields : function(items)
8623 Roo.each(items, function(i){
8625 var f = this.findField(i);
8638 Roo.apply(Roo.bootstrap.Form, {
8665 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8666 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8667 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8668 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8671 this.maskEl.top.enableDisplayMode("block");
8672 this.maskEl.left.enableDisplayMode("block");
8673 this.maskEl.bottom.enableDisplayMode("block");
8674 this.maskEl.right.enableDisplayMode("block");
8676 this.toolTip = new Roo.bootstrap.Tooltip({
8677 cls : 'roo-form-error-popover',
8679 'left' : ['r-l', [-2,0], 'right'],
8680 'right' : ['l-r', [2,0], 'left'],
8681 'bottom' : ['tl-bl', [0,2], 'top'],
8682 'top' : [ 'bl-tl', [0,-2], 'bottom']
8686 this.toolTip.render(Roo.get(document.body));
8688 this.toolTip.el.enableDisplayMode("block");
8690 Roo.get(document.body).on('click', function(){
8694 Roo.get(document.body).on('touchstart', function(){
8698 this.isApplied = true
8701 mask : function(form, target)
8705 this.target = target;
8707 if(!this.form.errorMask || !target.el){
8711 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8713 Roo.log(scrollable);
8715 var ot = this.target.el.calcOffsetsTo(scrollable);
8717 var scrollTo = ot[1] - this.form.maskOffset;
8719 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8721 scrollable.scrollTo('top', scrollTo);
8723 var box = this.target.el.getBox();
8725 var zIndex = Roo.bootstrap.Modal.zIndex++;
8728 this.maskEl.top.setStyle('position', 'absolute');
8729 this.maskEl.top.setStyle('z-index', zIndex);
8730 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8731 this.maskEl.top.setLeft(0);
8732 this.maskEl.top.setTop(0);
8733 this.maskEl.top.show();
8735 this.maskEl.left.setStyle('position', 'absolute');
8736 this.maskEl.left.setStyle('z-index', zIndex);
8737 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8738 this.maskEl.left.setLeft(0);
8739 this.maskEl.left.setTop(box.y - this.padding);
8740 this.maskEl.left.show();
8742 this.maskEl.bottom.setStyle('position', 'absolute');
8743 this.maskEl.bottom.setStyle('z-index', zIndex);
8744 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8745 this.maskEl.bottom.setLeft(0);
8746 this.maskEl.bottom.setTop(box.bottom + this.padding);
8747 this.maskEl.bottom.show();
8749 this.maskEl.right.setStyle('position', 'absolute');
8750 this.maskEl.right.setStyle('z-index', zIndex);
8751 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8752 this.maskEl.right.setLeft(box.right + this.padding);
8753 this.maskEl.right.setTop(box.y - this.padding);
8754 this.maskEl.right.show();
8756 this.toolTip.bindEl = this.target.el;
8758 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8760 var tip = this.target.blankText;
8762 if(this.target.getValue() !== '' ) {
8764 if (this.target.invalidText.length) {
8765 tip = this.target.invalidText;
8766 } else if (this.target.regexText.length){
8767 tip = this.target.regexText;
8771 this.toolTip.show(tip);
8773 this.intervalID = window.setInterval(function() {
8774 Roo.bootstrap.Form.popover.unmask();
8777 window.onwheel = function(){ return false;};
8779 (function(){ this.isMasked = true; }).defer(500, this);
8785 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8789 this.maskEl.top.setStyle('position', 'absolute');
8790 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8791 this.maskEl.top.hide();
8793 this.maskEl.left.setStyle('position', 'absolute');
8794 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8795 this.maskEl.left.hide();
8797 this.maskEl.bottom.setStyle('position', 'absolute');
8798 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8799 this.maskEl.bottom.hide();
8801 this.maskEl.right.setStyle('position', 'absolute');
8802 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8803 this.maskEl.right.hide();
8805 this.toolTip.hide();
8807 this.toolTip.el.hide();
8809 window.onwheel = function(){ return true;};
8811 if(this.intervalID){
8812 window.clearInterval(this.intervalID);
8813 this.intervalID = false;
8816 this.isMasked = false;
8826 * Ext JS Library 1.1.1
8827 * Copyright(c) 2006-2007, Ext JS, LLC.
8829 * Originally Released Under LGPL - original licence link has changed is not relivant.
8832 * <script type="text/javascript">
8835 * @class Roo.form.VTypes
8836 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8839 Roo.form.VTypes = function(){
8840 // closure these in so they are only created once.
8841 var alpha = /^[a-zA-Z_]+$/;
8842 var alphanum = /^[a-zA-Z0-9_]+$/;
8843 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8844 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8846 // All these messages and functions are configurable
8849 * The function used to validate email addresses
8850 * @param {String} value The email address
8852 'email' : function(v){
8853 return email.test(v);
8856 * The error text to display when the email validation function returns false
8859 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8861 * The keystroke filter mask to be applied on email input
8864 'emailMask' : /[a-z0-9_\.\-@]/i,
8867 * The function used to validate URLs
8868 * @param {String} value The URL
8870 'url' : function(v){
8874 * The error text to display when the url validation function returns false
8877 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8880 * The function used to validate alpha values
8881 * @param {String} value The value
8883 'alpha' : function(v){
8884 return alpha.test(v);
8887 * The error text to display when the alpha validation function returns false
8890 'alphaText' : 'This field should only contain letters and _',
8892 * The keystroke filter mask to be applied on alpha input
8895 'alphaMask' : /[a-z_]/i,
8898 * The function used to validate alphanumeric values
8899 * @param {String} value The value
8901 'alphanum' : function(v){
8902 return alphanum.test(v);
8905 * The error text to display when the alphanumeric validation function returns false
8908 'alphanumText' : 'This field should only contain letters, numbers and _',
8910 * The keystroke filter mask to be applied on alphanumeric input
8913 'alphanumMask' : /[a-z0-9_]/i
8923 * @class Roo.bootstrap.Input
8924 * @extends Roo.bootstrap.Component
8925 * Bootstrap Input class
8926 * @cfg {Boolean} disabled is it disabled
8927 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8928 * @cfg {String} name name of the input
8929 * @cfg {string} fieldLabel - the label associated
8930 * @cfg {string} placeholder - placeholder to put in text.
8931 * @cfg {string} before - input group add on before
8932 * @cfg {string} after - input group add on after
8933 * @cfg {string} size - (lg|sm) or leave empty..
8934 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8935 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8936 * @cfg {Number} md colspan out of 12 for computer-sized screens
8937 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8938 * @cfg {string} value default value of the input
8939 * @cfg {Number} labelWidth set the width of label
8940 * @cfg {Number} labellg set the width of label (1-12)
8941 * @cfg {Number} labelmd set the width of label (1-12)
8942 * @cfg {Number} labelsm set the width of label (1-12)
8943 * @cfg {Number} labelxs set the width of label (1-12)
8944 * @cfg {String} labelAlign (top|left)
8945 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8946 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8947 * @cfg {String} indicatorpos (left|right) default left
8948 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8949 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8951 * @cfg {String} align (left|center|right) Default left
8952 * @cfg {Boolean} forceFeedback (true|false) Default false
8955 * Create a new Input
8956 * @param {Object} config The config object
8959 Roo.bootstrap.Input = function(config){
8961 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8966 * Fires when this field receives input focus.
8967 * @param {Roo.form.Field} this
8972 * Fires when this field loses input focus.
8973 * @param {Roo.form.Field} this
8978 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8979 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8980 * @param {Roo.form.Field} this
8981 * @param {Roo.EventObject} e The event object
8986 * Fires just before the field blurs if the field value has changed.
8987 * @param {Roo.form.Field} this
8988 * @param {Mixed} newValue The new value
8989 * @param {Mixed} oldValue The original value
8994 * Fires after the field has been marked as invalid.
8995 * @param {Roo.form.Field} this
8996 * @param {String} msg The validation message
9001 * Fires after the field has been validated with no errors.
9002 * @param {Roo.form.Field} this
9007 * Fires after the key up
9008 * @param {Roo.form.Field} this
9009 * @param {Roo.EventObject} e The event Object
9015 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9017 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9018 automatic validation (defaults to "keyup").
9020 validationEvent : "keyup",
9022 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9024 validateOnBlur : true,
9026 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9028 validationDelay : 250,
9030 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9032 focusClass : "x-form-focus", // not needed???
9036 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9038 invalidClass : "has-warning",
9041 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9043 validClass : "has-success",
9046 * @cfg {Boolean} hasFeedback (true|false) default true
9051 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9053 invalidFeedbackClass : "glyphicon-warning-sign",
9056 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9058 validFeedbackClass : "glyphicon-ok",
9061 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9063 selectOnFocus : false,
9066 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9070 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9075 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9077 disableKeyFilter : false,
9080 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9084 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9088 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9090 blankText : "Please complete this mandatory field",
9093 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9097 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9099 maxLength : Number.MAX_VALUE,
9101 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9103 minLengthText : "The minimum length for this field is {0}",
9105 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9107 maxLengthText : "The maximum length for this field is {0}",
9111 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9112 * If available, this function will be called only after the basic validators all return true, and will be passed the
9113 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9117 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9118 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9119 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9123 * @cfg {String} regexText -- Depricated - use Invalid Text
9128 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9134 autocomplete: false,
9153 formatedValue : false,
9154 forceFeedback : false,
9156 indicatorpos : 'left',
9166 parentLabelAlign : function()
9169 while (parent.parent()) {
9170 parent = parent.parent();
9171 if (typeof(parent.labelAlign) !='undefined') {
9172 return parent.labelAlign;
9179 getAutoCreate : function()
9181 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9187 if(this.inputType != 'hidden'){
9188 cfg.cls = 'form-group' //input-group
9194 type : this.inputType,
9196 cls : 'form-control',
9197 placeholder : this.placeholder || '',
9198 autocomplete : this.autocomplete || 'new-password'
9201 if(this.capture.length){
9202 input.capture = this.capture;
9205 if(this.accept.length){
9206 input.accept = this.accept + "/*";
9210 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9213 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9214 input.maxLength = this.maxLength;
9217 if (this.disabled) {
9218 input.disabled=true;
9221 if (this.readOnly) {
9222 input.readonly=true;
9226 input.name = this.name;
9230 input.cls += ' input-' + this.size;
9234 ['xs','sm','md','lg'].map(function(size){
9235 if (settings[size]) {
9236 cfg.cls += ' col-' + size + '-' + settings[size];
9240 var inputblock = input;
9244 cls: 'glyphicon form-control-feedback'
9247 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9250 cls : 'has-feedback',
9258 if (this.before || this.after) {
9261 cls : 'input-group',
9265 if (this.before && typeof(this.before) == 'string') {
9267 inputblock.cn.push({
9269 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9273 if (this.before && typeof(this.before) == 'object') {
9274 this.before = Roo.factory(this.before);
9276 inputblock.cn.push({
9278 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9279 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9283 inputblock.cn.push(input);
9285 if (this.after && typeof(this.after) == 'string') {
9286 inputblock.cn.push({
9288 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9292 if (this.after && typeof(this.after) == 'object') {
9293 this.after = Roo.factory(this.after);
9295 inputblock.cn.push({
9297 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9298 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9302 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9303 inputblock.cls += ' has-feedback';
9304 inputblock.cn.push(feedback);
9309 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9310 tooltip : 'This field is required'
9312 if (Roo.bootstrap.version == 4) {
9315 style : 'display-none'
9318 if (align ==='left' && this.fieldLabel.length) {
9320 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9327 cls : 'control-label col-form-label',
9328 html : this.fieldLabel
9339 var labelCfg = cfg.cn[1];
9340 var contentCfg = cfg.cn[2];
9342 if(this.indicatorpos == 'right'){
9347 cls : 'control-label col-form-label',
9351 html : this.fieldLabel
9365 labelCfg = cfg.cn[0];
9366 contentCfg = cfg.cn[1];
9370 if(this.labelWidth > 12){
9371 labelCfg.style = "width: " + this.labelWidth + 'px';
9374 if(this.labelWidth < 13 && this.labelmd == 0){
9375 this.labelmd = this.labelWidth;
9378 if(this.labellg > 0){
9379 labelCfg.cls += ' col-lg-' + this.labellg;
9380 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9383 if(this.labelmd > 0){
9384 labelCfg.cls += ' col-md-' + this.labelmd;
9385 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9388 if(this.labelsm > 0){
9389 labelCfg.cls += ' col-sm-' + this.labelsm;
9390 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9393 if(this.labelxs > 0){
9394 labelCfg.cls += ' col-xs-' + this.labelxs;
9395 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9399 } else if ( this.fieldLabel.length) {
9404 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9405 tooltip : 'This field is required'
9409 //cls : 'input-group-addon',
9410 html : this.fieldLabel
9418 if(this.indicatorpos == 'right'){
9423 //cls : 'input-group-addon',
9424 html : this.fieldLabel
9429 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9430 tooltip : 'This field is required'
9450 if (this.parentType === 'Navbar' && this.parent().bar) {
9451 cfg.cls += ' navbar-form';
9454 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9455 // on BS4 we do this only if not form
9456 cfg.cls += ' navbar-form';
9464 * return the real input element.
9466 inputEl: function ()
9468 return this.el.select('input.form-control',true).first();
9471 tooltipEl : function()
9473 return this.inputEl();
9476 indicatorEl : function()
9478 if (Roo.bootstrap.version == 4) {
9479 return false; // not enabled in v4 yet.
9482 var indicator = this.el.select('i.roo-required-indicator',true).first();
9492 setDisabled : function(v)
9494 var i = this.inputEl().dom;
9496 i.removeAttribute('disabled');
9500 i.setAttribute('disabled','true');
9502 initEvents : function()
9505 this.inputEl().on("keydown" , this.fireKey, this);
9506 this.inputEl().on("focus", this.onFocus, this);
9507 this.inputEl().on("blur", this.onBlur, this);
9509 this.inputEl().relayEvent('keyup', this);
9511 this.indicator = this.indicatorEl();
9514 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9517 // reference to original value for reset
9518 this.originalValue = this.getValue();
9519 //Roo.form.TextField.superclass.initEvents.call(this);
9520 if(this.validationEvent == 'keyup'){
9521 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9522 this.inputEl().on('keyup', this.filterValidation, this);
9524 else if(this.validationEvent !== false){
9525 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9528 if(this.selectOnFocus){
9529 this.on("focus", this.preFocus, this);
9532 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9533 this.inputEl().on("keypress", this.filterKeys, this);
9535 this.inputEl().relayEvent('keypress', this);
9538 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9539 this.el.on("click", this.autoSize, this);
9542 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9543 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9546 if (typeof(this.before) == 'object') {
9547 this.before.render(this.el.select('.roo-input-before',true).first());
9549 if (typeof(this.after) == 'object') {
9550 this.after.render(this.el.select('.roo-input-after',true).first());
9553 this.inputEl().on('change', this.onChange, this);
9556 filterValidation : function(e){
9557 if(!e.isNavKeyPress()){
9558 this.validationTask.delay(this.validationDelay);
9562 * Validates the field value
9563 * @return {Boolean} True if the value is valid, else false
9565 validate : function(){
9566 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9567 if(this.disabled || this.validateValue(this.getRawValue())){
9578 * Validates a value according to the field's validation rules and marks the field as invalid
9579 * if the validation fails
9580 * @param {Mixed} value The value to validate
9581 * @return {Boolean} True if the value is valid, else false
9583 validateValue : function(value)
9585 if(this.getVisibilityEl().hasClass('hidden')){
9589 if(value.length < 1) { // if it's blank
9590 if(this.allowBlank){
9596 if(value.length < this.minLength){
9599 if(value.length > this.maxLength){
9603 var vt = Roo.form.VTypes;
9604 if(!vt[this.vtype](value, this)){
9608 if(typeof this.validator == "function"){
9609 var msg = this.validator(value);
9613 if (typeof(msg) == 'string') {
9614 this.invalidText = msg;
9618 if(this.regex && !this.regex.test(value)){
9626 fireKey : function(e){
9627 //Roo.log('field ' + e.getKey());
9628 if(e.isNavKeyPress()){
9629 this.fireEvent("specialkey", this, e);
9632 focus : function (selectText){
9634 this.inputEl().focus();
9635 if(selectText === true){
9636 this.inputEl().dom.select();
9642 onFocus : function(){
9643 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9644 // this.el.addClass(this.focusClass);
9647 this.hasFocus = true;
9648 this.startValue = this.getValue();
9649 this.fireEvent("focus", this);
9653 beforeBlur : Roo.emptyFn,
9657 onBlur : function(){
9659 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9660 //this.el.removeClass(this.focusClass);
9662 this.hasFocus = false;
9663 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9666 var v = this.getValue();
9667 if(String(v) !== String(this.startValue)){
9668 this.fireEvent('change', this, v, this.startValue);
9670 this.fireEvent("blur", this);
9673 onChange : function(e)
9675 var v = this.getValue();
9676 if(String(v) !== String(this.startValue)){
9677 this.fireEvent('change', this, v, this.startValue);
9683 * Resets the current field value to the originally loaded value and clears any validation messages
9686 this.setValue(this.originalValue);
9690 * Returns the name of the field
9691 * @return {Mixed} name The name field
9693 getName: function(){
9697 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9698 * @return {Mixed} value The field value
9700 getValue : function(){
9702 var v = this.inputEl().getValue();
9707 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9708 * @return {Mixed} value The field value
9710 getRawValue : function(){
9711 var v = this.inputEl().getValue();
9717 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9718 * @param {Mixed} value The value to set
9720 setRawValue : function(v){
9721 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9724 selectText : function(start, end){
9725 var v = this.getRawValue();
9727 start = start === undefined ? 0 : start;
9728 end = end === undefined ? v.length : end;
9729 var d = this.inputEl().dom;
9730 if(d.setSelectionRange){
9731 d.setSelectionRange(start, end);
9732 }else if(d.createTextRange){
9733 var range = d.createTextRange();
9734 range.moveStart("character", start);
9735 range.moveEnd("character", v.length-end);
9742 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9743 * @param {Mixed} value The value to set
9745 setValue : function(v){
9748 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9754 processValue : function(value){
9755 if(this.stripCharsRe){
9756 var newValue = value.replace(this.stripCharsRe, '');
9757 if(newValue !== value){
9758 this.setRawValue(newValue);
9765 preFocus : function(){
9767 if(this.selectOnFocus){
9768 this.inputEl().dom.select();
9771 filterKeys : function(e){
9773 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9776 var c = e.getCharCode(), cc = String.fromCharCode(c);
9777 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9780 if(!this.maskRe.test(cc)){
9785 * Clear any invalid styles/messages for this field
9787 clearInvalid : function(){
9789 if(!this.el || this.preventMark){ // not rendered
9794 this.el.removeClass([this.invalidClass, 'is-invalid']);
9796 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9798 var feedback = this.el.select('.form-control-feedback', true).first();
9801 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9807 this.indicator.removeClass('visible');
9808 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9811 this.fireEvent('valid', this);
9815 * Mark this field as valid
9817 markValid : function()
9819 if(!this.el || this.preventMark){ // not rendered...
9823 this.el.removeClass([this.invalidClass, this.validClass]);
9824 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9826 var feedback = this.el.select('.form-control-feedback', true).first();
9829 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9833 this.indicator.removeClass('visible');
9834 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9841 if(this.allowBlank && !this.getRawValue().length){
9844 if (Roo.bootstrap.version == 3) {
9845 this.el.addClass(this.validClass);
9847 this.inputEl().addClass('is-valid');
9850 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9852 var feedback = this.el.select('.form-control-feedback', true).first();
9855 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9856 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9861 this.fireEvent('valid', this);
9865 * Mark this field as invalid
9866 * @param {String} msg The validation message
9868 markInvalid : function(msg)
9870 if(!this.el || this.preventMark){ // not rendered
9874 this.el.removeClass([this.invalidClass, this.validClass]);
9875 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9877 var feedback = this.el.select('.form-control-feedback', true).first();
9880 this.el.select('.form-control-feedback', true).first().removeClass(
9881 [this.invalidFeedbackClass, this.validFeedbackClass]);
9888 if(this.allowBlank && !this.getRawValue().length){
9893 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9894 this.indicator.addClass('visible');
9896 if (Roo.bootstrap.version == 3) {
9897 this.el.addClass(this.invalidClass);
9899 this.inputEl().addClass('is-invalid');
9904 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9906 var feedback = this.el.select('.form-control-feedback', true).first();
9909 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9911 if(this.getValue().length || this.forceFeedback){
9912 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9919 this.fireEvent('invalid', this, msg);
9922 SafariOnKeyDown : function(event)
9924 // this is a workaround for a password hang bug on chrome/ webkit.
9925 if (this.inputEl().dom.type != 'password') {
9929 var isSelectAll = false;
9931 if(this.inputEl().dom.selectionEnd > 0){
9932 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9934 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9935 event.preventDefault();
9940 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9942 event.preventDefault();
9943 // this is very hacky as keydown always get's upper case.
9945 var cc = String.fromCharCode(event.getCharCode());
9946 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9950 adjustWidth : function(tag, w){
9951 tag = tag.toLowerCase();
9952 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9953 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9957 if(tag == 'textarea'){
9960 }else if(Roo.isOpera){
9964 if(tag == 'textarea'){
9972 setFieldLabel : function(v)
9978 if(this.indicatorEl()){
9979 var ar = this.el.select('label > span',true);
9981 if (ar.elements.length) {
9982 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9983 this.fieldLabel = v;
9987 var br = this.el.select('label',true);
9989 if(br.elements.length) {
9990 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9991 this.fieldLabel = v;
9995 Roo.log('Cannot Found any of label > span || label in input');
9999 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10000 this.fieldLabel = v;
10015 * @class Roo.bootstrap.TextArea
10016 * @extends Roo.bootstrap.Input
10017 * Bootstrap TextArea class
10018 * @cfg {Number} cols Specifies the visible width of a text area
10019 * @cfg {Number} rows Specifies the visible number of lines in a text area
10020 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10021 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10022 * @cfg {string} html text
10025 * Create a new TextArea
10026 * @param {Object} config The config object
10029 Roo.bootstrap.TextArea = function(config){
10030 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10034 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10044 getAutoCreate : function(){
10046 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10052 if(this.inputType != 'hidden'){
10053 cfg.cls = 'form-group' //input-group
10061 value : this.value || '',
10062 html: this.html || '',
10063 cls : 'form-control',
10064 placeholder : this.placeholder || ''
10068 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10069 input.maxLength = this.maxLength;
10073 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10077 input.cols = this.cols;
10080 if (this.readOnly) {
10081 input.readonly = true;
10085 input.name = this.name;
10089 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10093 ['xs','sm','md','lg'].map(function(size){
10094 if (settings[size]) {
10095 cfg.cls += ' col-' + size + '-' + settings[size];
10099 var inputblock = input;
10101 if(this.hasFeedback && !this.allowBlank){
10105 cls: 'glyphicon form-control-feedback'
10109 cls : 'has-feedback',
10118 if (this.before || this.after) {
10121 cls : 'input-group',
10125 inputblock.cn.push({
10127 cls : 'input-group-addon',
10132 inputblock.cn.push(input);
10134 if(this.hasFeedback && !this.allowBlank){
10135 inputblock.cls += ' has-feedback';
10136 inputblock.cn.push(feedback);
10140 inputblock.cn.push({
10142 cls : 'input-group-addon',
10149 if (align ==='left' && this.fieldLabel.length) {
10154 cls : 'control-label',
10155 html : this.fieldLabel
10166 if(this.labelWidth > 12){
10167 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10170 if(this.labelWidth < 13 && this.labelmd == 0){
10171 this.labelmd = this.labelWidth;
10174 if(this.labellg > 0){
10175 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10176 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10179 if(this.labelmd > 0){
10180 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10181 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10184 if(this.labelsm > 0){
10185 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10186 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10189 if(this.labelxs > 0){
10190 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10191 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10194 } else if ( this.fieldLabel.length) {
10199 //cls : 'input-group-addon',
10200 html : this.fieldLabel
10218 if (this.disabled) {
10219 input.disabled=true;
10226 * return the real textarea element.
10228 inputEl: function ()
10230 return this.el.select('textarea.form-control',true).first();
10234 * Clear any invalid styles/messages for this field
10236 clearInvalid : function()
10239 if(!this.el || this.preventMark){ // not rendered
10243 var label = this.el.select('label', true).first();
10244 var icon = this.el.select('i.fa-star', true).first();
10249 this.el.removeClass( this.validClass);
10250 this.inputEl().removeClass('is-invalid');
10252 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10254 var feedback = this.el.select('.form-control-feedback', true).first();
10257 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10262 this.fireEvent('valid', this);
10266 * Mark this field as valid
10268 markValid : function()
10270 if(!this.el || this.preventMark){ // not rendered
10274 this.el.removeClass([this.invalidClass, this.validClass]);
10275 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10277 var feedback = this.el.select('.form-control-feedback', true).first();
10280 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10283 if(this.disabled || this.allowBlank){
10287 var label = this.el.select('label', true).first();
10288 var icon = this.el.select('i.fa-star', true).first();
10293 if (Roo.bootstrap.version == 3) {
10294 this.el.addClass(this.validClass);
10296 this.inputEl().addClass('is-valid');
10300 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10302 var feedback = this.el.select('.form-control-feedback', true).first();
10305 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10306 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10311 this.fireEvent('valid', this);
10315 * Mark this field as invalid
10316 * @param {String} msg The validation message
10318 markInvalid : function(msg)
10320 if(!this.el || this.preventMark){ // not rendered
10324 this.el.removeClass([this.invalidClass, this.validClass]);
10325 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10327 var feedback = this.el.select('.form-control-feedback', true).first();
10330 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10333 if(this.disabled || this.allowBlank){
10337 var label = this.el.select('label', true).first();
10338 var icon = this.el.select('i.fa-star', true).first();
10340 if(!this.getValue().length && label && !icon){
10341 this.el.createChild({
10343 cls : 'text-danger fa fa-lg fa-star',
10344 tooltip : 'This field is required',
10345 style : 'margin-right:5px;'
10349 if (Roo.bootstrap.version == 3) {
10350 this.el.addClass(this.invalidClass);
10352 this.inputEl().addClass('is-invalid');
10355 // fixme ... this may be depricated need to test..
10356 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10358 var feedback = this.el.select('.form-control-feedback', true).first();
10361 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10363 if(this.getValue().length || this.forceFeedback){
10364 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10371 this.fireEvent('invalid', this, msg);
10379 * trigger field - base class for combo..
10384 * @class Roo.bootstrap.TriggerField
10385 * @extends Roo.bootstrap.Input
10386 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10387 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10388 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10389 * for which you can provide a custom implementation. For example:
10391 var trigger = new Roo.bootstrap.TriggerField();
10392 trigger.onTriggerClick = myTriggerFn;
10393 trigger.applyTo('my-field');
10396 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10397 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10398 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10399 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10400 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10403 * Create a new TriggerField.
10404 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10405 * to the base TextField)
10407 Roo.bootstrap.TriggerField = function(config){
10408 this.mimicing = false;
10409 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10412 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10414 * @cfg {String} triggerClass A CSS class to apply to the trigger
10417 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10422 * @cfg {Boolean} removable (true|false) special filter default false
10426 /** @cfg {Boolean} grow @hide */
10427 /** @cfg {Number} growMin @hide */
10428 /** @cfg {Number} growMax @hide */
10434 autoSize: Roo.emptyFn,
10438 deferHeight : true,
10441 actionMode : 'wrap',
10446 getAutoCreate : function(){
10448 var align = this.labelAlign || this.parentLabelAlign();
10453 cls: 'form-group' //input-group
10460 type : this.inputType,
10461 cls : 'form-control',
10462 autocomplete: 'new-password',
10463 placeholder : this.placeholder || ''
10467 input.name = this.name;
10470 input.cls += ' input-' + this.size;
10473 if (this.disabled) {
10474 input.disabled=true;
10477 var inputblock = input;
10479 if(this.hasFeedback && !this.allowBlank){
10483 cls: 'glyphicon form-control-feedback'
10486 if(this.removable && !this.editable && !this.tickable){
10488 cls : 'has-feedback',
10494 cls : 'roo-combo-removable-btn close'
10501 cls : 'has-feedback',
10510 if(this.removable && !this.editable && !this.tickable){
10512 cls : 'roo-removable',
10518 cls : 'roo-combo-removable-btn close'
10525 if (this.before || this.after) {
10528 cls : 'input-group',
10532 inputblock.cn.push({
10534 cls : 'input-group-addon input-group-prepend input-group-text',
10539 inputblock.cn.push(input);
10541 if(this.hasFeedback && !this.allowBlank){
10542 inputblock.cls += ' has-feedback';
10543 inputblock.cn.push(feedback);
10547 inputblock.cn.push({
10549 cls : 'input-group-addon input-group-append input-group-text',
10558 var ibwrap = inputblock;
10563 cls: 'roo-select2-choices',
10567 cls: 'roo-select2-search-field',
10579 cls: 'roo-select2-container input-group',
10584 cls: 'form-hidden-field'
10590 if(!this.multiple && this.showToggleBtn){
10596 if (this.caret != false) {
10599 cls: 'fa fa-' + this.caret
10606 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10611 cls: 'combobox-clear',
10625 combobox.cls += ' roo-select2-container-multi';
10629 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10630 tooltip : 'This field is required'
10632 if (Roo.bootstrap.version == 4) {
10635 style : 'display:none'
10640 if (align ==='left' && this.fieldLabel.length) {
10642 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10649 cls : 'control-label',
10650 html : this.fieldLabel
10662 var labelCfg = cfg.cn[1];
10663 var contentCfg = cfg.cn[2];
10665 if(this.indicatorpos == 'right'){
10670 cls : 'control-label',
10674 html : this.fieldLabel
10688 labelCfg = cfg.cn[0];
10689 contentCfg = cfg.cn[1];
10692 if(this.labelWidth > 12){
10693 labelCfg.style = "width: " + this.labelWidth + 'px';
10696 if(this.labelWidth < 13 && this.labelmd == 0){
10697 this.labelmd = this.labelWidth;
10700 if(this.labellg > 0){
10701 labelCfg.cls += ' col-lg-' + this.labellg;
10702 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10705 if(this.labelmd > 0){
10706 labelCfg.cls += ' col-md-' + this.labelmd;
10707 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10710 if(this.labelsm > 0){
10711 labelCfg.cls += ' col-sm-' + this.labelsm;
10712 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10715 if(this.labelxs > 0){
10716 labelCfg.cls += ' col-xs-' + this.labelxs;
10717 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10720 } else if ( this.fieldLabel.length) {
10721 // Roo.log(" label");
10726 //cls : 'input-group-addon',
10727 html : this.fieldLabel
10735 if(this.indicatorpos == 'right'){
10743 html : this.fieldLabel
10757 // Roo.log(" no label && no align");
10764 ['xs','sm','md','lg'].map(function(size){
10765 if (settings[size]) {
10766 cfg.cls += ' col-' + size + '-' + settings[size];
10777 onResize : function(w, h){
10778 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10779 // if(typeof w == 'number'){
10780 // var x = w - this.trigger.getWidth();
10781 // this.inputEl().setWidth(this.adjustWidth('input', x));
10782 // this.trigger.setStyle('left', x+'px');
10787 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10790 getResizeEl : function(){
10791 return this.inputEl();
10795 getPositionEl : function(){
10796 return this.inputEl();
10800 alignErrorIcon : function(){
10801 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10805 initEvents : function(){
10809 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10810 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10811 if(!this.multiple && this.showToggleBtn){
10812 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10813 if(this.hideTrigger){
10814 this.trigger.setDisplayed(false);
10816 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10820 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10823 if(this.removable && !this.editable && !this.tickable){
10824 var close = this.closeTriggerEl();
10827 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10828 close.on('click', this.removeBtnClick, this, close);
10832 //this.trigger.addClassOnOver('x-form-trigger-over');
10833 //this.trigger.addClassOnClick('x-form-trigger-click');
10836 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10840 closeTriggerEl : function()
10842 var close = this.el.select('.roo-combo-removable-btn', true).first();
10843 return close ? close : false;
10846 removeBtnClick : function(e, h, el)
10848 e.preventDefault();
10850 if(this.fireEvent("remove", this) !== false){
10852 this.fireEvent("afterremove", this)
10856 createList : function()
10858 this.list = Roo.get(document.body).createChild({
10859 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10860 cls: 'typeahead typeahead-long dropdown-menu',
10861 style: 'display:none'
10864 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10869 initTrigger : function(){
10874 onDestroy : function(){
10876 this.trigger.removeAllListeners();
10877 // this.trigger.remove();
10880 // this.wrap.remove();
10882 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10886 onFocus : function(){
10887 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10889 if(!this.mimicing){
10890 this.wrap.addClass('x-trigger-wrap-focus');
10891 this.mimicing = true;
10892 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10893 if(this.monitorTab){
10894 this.el.on("keydown", this.checkTab, this);
10901 checkTab : function(e){
10902 if(e.getKey() == e.TAB){
10903 this.triggerBlur();
10908 onBlur : function(){
10913 mimicBlur : function(e, t){
10915 if(!this.wrap.contains(t) && this.validateBlur()){
10916 this.triggerBlur();
10922 triggerBlur : function(){
10923 this.mimicing = false;
10924 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10925 if(this.monitorTab){
10926 this.el.un("keydown", this.checkTab, this);
10928 //this.wrap.removeClass('x-trigger-wrap-focus');
10929 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10933 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10934 validateBlur : function(e, t){
10939 onDisable : function(){
10940 this.inputEl().dom.disabled = true;
10941 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10943 // this.wrap.addClass('x-item-disabled');
10948 onEnable : function(){
10949 this.inputEl().dom.disabled = false;
10950 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10952 // this.el.removeClass('x-item-disabled');
10957 onShow : function(){
10958 var ae = this.getActionEl();
10961 ae.dom.style.display = '';
10962 ae.dom.style.visibility = 'visible';
10968 onHide : function(){
10969 var ae = this.getActionEl();
10970 ae.dom.style.display = 'none';
10974 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10975 * by an implementing function.
10977 * @param {EventObject} e
10979 onTriggerClick : Roo.emptyFn
10983 * Ext JS Library 1.1.1
10984 * Copyright(c) 2006-2007, Ext JS, LLC.
10986 * Originally Released Under LGPL - original licence link has changed is not relivant.
10989 * <script type="text/javascript">
10994 * @class Roo.data.SortTypes
10996 * Defines the default sorting (casting?) comparison functions used when sorting data.
10998 Roo.data.SortTypes = {
11000 * Default sort that does nothing
11001 * @param {Mixed} s The value being converted
11002 * @return {Mixed} The comparison value
11004 none : function(s){
11009 * The regular expression used to strip tags
11013 stripTagsRE : /<\/?[^>]+>/gi,
11016 * Strips all HTML tags to sort on text only
11017 * @param {Mixed} s The value being converted
11018 * @return {String} The comparison value
11020 asText : function(s){
11021 return String(s).replace(this.stripTagsRE, "");
11025 * Strips all HTML tags to sort on text only - Case insensitive
11026 * @param {Mixed} s The value being converted
11027 * @return {String} The comparison value
11029 asUCText : function(s){
11030 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11034 * Case insensitive string
11035 * @param {Mixed} s The value being converted
11036 * @return {String} The comparison value
11038 asUCString : function(s) {
11039 return String(s).toUpperCase();
11044 * @param {Mixed} s The value being converted
11045 * @return {Number} The comparison value
11047 asDate : function(s) {
11051 if(s instanceof Date){
11052 return s.getTime();
11054 return Date.parse(String(s));
11059 * @param {Mixed} s The value being converted
11060 * @return {Float} The comparison value
11062 asFloat : function(s) {
11063 var val = parseFloat(String(s).replace(/,/g, ""));
11072 * @param {Mixed} s The value being converted
11073 * @return {Number} The comparison value
11075 asInt : function(s) {
11076 var val = parseInt(String(s).replace(/,/g, ""));
11084 * Ext JS Library 1.1.1
11085 * Copyright(c) 2006-2007, Ext JS, LLC.
11087 * Originally Released Under LGPL - original licence link has changed is not relivant.
11090 * <script type="text/javascript">
11094 * @class Roo.data.Record
11095 * Instances of this class encapsulate both record <em>definition</em> information, and record
11096 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11097 * to access Records cached in an {@link Roo.data.Store} object.<br>
11099 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11100 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11103 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11105 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11106 * {@link #create}. The parameters are the same.
11107 * @param {Array} data An associative Array of data values keyed by the field name.
11108 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11109 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11110 * not specified an integer id is generated.
11112 Roo.data.Record = function(data, id){
11113 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11118 * Generate a constructor for a specific record layout.
11119 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11120 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11121 * Each field definition object may contain the following properties: <ul>
11122 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
11123 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11124 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11125 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11126 * is being used, then this is a string containing the javascript expression to reference the data relative to
11127 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11128 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11129 * this may be omitted.</p></li>
11130 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11131 * <ul><li>auto (Default, implies no conversion)</li>
11136 * <li>date</li></ul></p></li>
11137 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11138 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11139 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11140 * by the Reader into an object that will be stored in the Record. It is passed the
11141 * following parameters:<ul>
11142 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11144 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11146 * <br>usage:<br><pre><code>
11147 var TopicRecord = Roo.data.Record.create(
11148 {name: 'title', mapping: 'topic_title'},
11149 {name: 'author', mapping: 'username'},
11150 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11151 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11152 {name: 'lastPoster', mapping: 'user2'},
11153 {name: 'excerpt', mapping: 'post_text'}
11156 var myNewRecord = new TopicRecord({
11157 title: 'Do my job please',
11160 lastPost: new Date(),
11161 lastPoster: 'Animal',
11162 excerpt: 'No way dude!'
11164 myStore.add(myNewRecord);
11169 Roo.data.Record.create = function(o){
11170 var f = function(){
11171 f.superclass.constructor.apply(this, arguments);
11173 Roo.extend(f, Roo.data.Record);
11174 var p = f.prototype;
11175 p.fields = new Roo.util.MixedCollection(false, function(field){
11178 for(var i = 0, len = o.length; i < len; i++){
11179 p.fields.add(new Roo.data.Field(o[i]));
11181 f.getField = function(name){
11182 return p.fields.get(name);
11187 Roo.data.Record.AUTO_ID = 1000;
11188 Roo.data.Record.EDIT = 'edit';
11189 Roo.data.Record.REJECT = 'reject';
11190 Roo.data.Record.COMMIT = 'commit';
11192 Roo.data.Record.prototype = {
11194 * Readonly flag - true if this record has been modified.
11203 join : function(store){
11204 this.store = store;
11208 * Set the named field to the specified value.
11209 * @param {String} name The name of the field to set.
11210 * @param {Object} value The value to set the field to.
11212 set : function(name, value){
11213 if(this.data[name] == value){
11217 if(!this.modified){
11218 this.modified = {};
11220 if(typeof this.modified[name] == 'undefined'){
11221 this.modified[name] = this.data[name];
11223 this.data[name] = value;
11224 if(!this.editing && this.store){
11225 this.store.afterEdit(this);
11230 * Get the value of the named field.
11231 * @param {String} name The name of the field to get the value of.
11232 * @return {Object} The value of the field.
11234 get : function(name){
11235 return this.data[name];
11239 beginEdit : function(){
11240 this.editing = true;
11241 this.modified = {};
11245 cancelEdit : function(){
11246 this.editing = false;
11247 delete this.modified;
11251 endEdit : function(){
11252 this.editing = false;
11253 if(this.dirty && this.store){
11254 this.store.afterEdit(this);
11259 * Usually called by the {@link Roo.data.Store} which owns the Record.
11260 * Rejects all changes made to the Record since either creation, or the last commit operation.
11261 * Modified fields are reverted to their original values.
11263 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11264 * of reject operations.
11266 reject : function(){
11267 var m = this.modified;
11269 if(typeof m[n] != "function"){
11270 this.data[n] = m[n];
11273 this.dirty = false;
11274 delete this.modified;
11275 this.editing = false;
11277 this.store.afterReject(this);
11282 * Usually called by the {@link Roo.data.Store} which owns the Record.
11283 * Commits all changes made to the Record since either creation, or the last commit operation.
11285 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11286 * of commit operations.
11288 commit : function(){
11289 this.dirty = false;
11290 delete this.modified;
11291 this.editing = false;
11293 this.store.afterCommit(this);
11298 hasError : function(){
11299 return this.error != null;
11303 clearError : function(){
11308 * Creates a copy of this record.
11309 * @param {String} id (optional) A new record id if you don't want to use this record's id
11312 copy : function(newId) {
11313 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11317 * Ext JS Library 1.1.1
11318 * Copyright(c) 2006-2007, Ext JS, LLC.
11320 * Originally Released Under LGPL - original licence link has changed is not relivant.
11323 * <script type="text/javascript">
11329 * @class Roo.data.Store
11330 * @extends Roo.util.Observable
11331 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11332 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11334 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
11335 * has no knowledge of the format of the data returned by the Proxy.<br>
11337 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11338 * instances from the data object. These records are cached and made available through accessor functions.
11340 * Creates a new Store.
11341 * @param {Object} config A config object containing the objects needed for the Store to access data,
11342 * and read the data into Records.
11344 Roo.data.Store = function(config){
11345 this.data = new Roo.util.MixedCollection(false);
11346 this.data.getKey = function(o){
11349 this.baseParams = {};
11351 this.paramNames = {
11356 "multisort" : "_multisort"
11359 if(config && config.data){
11360 this.inlineData = config.data;
11361 delete config.data;
11364 Roo.apply(this, config);
11366 if(this.reader){ // reader passed
11367 this.reader = Roo.factory(this.reader, Roo.data);
11368 this.reader.xmodule = this.xmodule || false;
11369 if(!this.recordType){
11370 this.recordType = this.reader.recordType;
11372 if(this.reader.onMetaChange){
11373 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11377 if(this.recordType){
11378 this.fields = this.recordType.prototype.fields;
11380 this.modified = [];
11384 * @event datachanged
11385 * Fires when the data cache has changed, and a widget which is using this Store
11386 * as a Record cache should refresh its view.
11387 * @param {Store} this
11389 datachanged : true,
11391 * @event metachange
11392 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11393 * @param {Store} this
11394 * @param {Object} meta The JSON metadata
11399 * Fires when Records have been added to the Store
11400 * @param {Store} this
11401 * @param {Roo.data.Record[]} records The array of Records added
11402 * @param {Number} index The index at which the record(s) were added
11407 * Fires when a Record has been removed from the Store
11408 * @param {Store} this
11409 * @param {Roo.data.Record} record The Record that was removed
11410 * @param {Number} index The index at which the record was removed
11415 * Fires when a Record has been updated
11416 * @param {Store} this
11417 * @param {Roo.data.Record} record The Record that was updated
11418 * @param {String} operation The update operation being performed. Value may be one of:
11420 Roo.data.Record.EDIT
11421 Roo.data.Record.REJECT
11422 Roo.data.Record.COMMIT
11428 * Fires when the data cache has been cleared.
11429 * @param {Store} this
11433 * @event beforeload
11434 * Fires before a request is made for a new data object. If the beforeload handler returns false
11435 * the load action will be canceled.
11436 * @param {Store} this
11437 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11441 * @event beforeloadadd
11442 * Fires after a new set of Records has been loaded.
11443 * @param {Store} this
11444 * @param {Roo.data.Record[]} records The Records that were loaded
11445 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11447 beforeloadadd : true,
11450 * Fires after a new set of Records has been loaded, before they are added to the store.
11451 * @param {Store} this
11452 * @param {Roo.data.Record[]} records The Records that were loaded
11453 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11454 * @params {Object} return from reader
11458 * @event loadexception
11459 * Fires if an exception occurs in the Proxy during loading.
11460 * Called with the signature of the Proxy's "loadexception" event.
11461 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11464 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11465 * @param {Object} load options
11466 * @param {Object} jsonData from your request (normally this contains the Exception)
11468 loadexception : true
11472 this.proxy = Roo.factory(this.proxy, Roo.data);
11473 this.proxy.xmodule = this.xmodule || false;
11474 this.relayEvents(this.proxy, ["loadexception"]);
11476 this.sortToggle = {};
11477 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11479 Roo.data.Store.superclass.constructor.call(this);
11481 if(this.inlineData){
11482 this.loadData(this.inlineData);
11483 delete this.inlineData;
11487 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11489 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11490 * without a remote query - used by combo/forms at present.
11494 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11497 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11500 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11501 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11504 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11505 * on any HTTP request
11508 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11511 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11515 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11516 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11518 remoteSort : false,
11521 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11522 * loaded or when a record is removed. (defaults to false).
11524 pruneModifiedRecords : false,
11527 lastOptions : null,
11530 * Add Records to the Store and fires the add event.
11531 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11533 add : function(records){
11534 records = [].concat(records);
11535 for(var i = 0, len = records.length; i < len; i++){
11536 records[i].join(this);
11538 var index = this.data.length;
11539 this.data.addAll(records);
11540 this.fireEvent("add", this, records, index);
11544 * Remove a Record from the Store and fires the remove event.
11545 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11547 remove : function(record){
11548 var index = this.data.indexOf(record);
11549 this.data.removeAt(index);
11551 if(this.pruneModifiedRecords){
11552 this.modified.remove(record);
11554 this.fireEvent("remove", this, record, index);
11558 * Remove all Records from the Store and fires the clear event.
11560 removeAll : function(){
11562 if(this.pruneModifiedRecords){
11563 this.modified = [];
11565 this.fireEvent("clear", this);
11569 * Inserts Records to the Store at the given index and fires the add event.
11570 * @param {Number} index The start index at which to insert the passed Records.
11571 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11573 insert : function(index, records){
11574 records = [].concat(records);
11575 for(var i = 0, len = records.length; i < len; i++){
11576 this.data.insert(index, records[i]);
11577 records[i].join(this);
11579 this.fireEvent("add", this, records, index);
11583 * Get the index within the cache of the passed Record.
11584 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11585 * @return {Number} The index of the passed Record. Returns -1 if not found.
11587 indexOf : function(record){
11588 return this.data.indexOf(record);
11592 * Get the index within the cache of the Record with the passed id.
11593 * @param {String} id The id of the Record to find.
11594 * @return {Number} The index of the Record. Returns -1 if not found.
11596 indexOfId : function(id){
11597 return this.data.indexOfKey(id);
11601 * Get the Record with the specified id.
11602 * @param {String} id The id of the Record to find.
11603 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11605 getById : function(id){
11606 return this.data.key(id);
11610 * Get the Record at the specified index.
11611 * @param {Number} index The index of the Record to find.
11612 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11614 getAt : function(index){
11615 return this.data.itemAt(index);
11619 * Returns a range of Records between specified indices.
11620 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11621 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11622 * @return {Roo.data.Record[]} An array of Records
11624 getRange : function(start, end){
11625 return this.data.getRange(start, end);
11629 storeOptions : function(o){
11630 o = Roo.apply({}, o);
11633 this.lastOptions = o;
11637 * Loads the Record cache from the configured Proxy using the configured Reader.
11639 * If using remote paging, then the first load call must specify the <em>start</em>
11640 * and <em>limit</em> properties in the options.params property to establish the initial
11641 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11643 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11644 * and this call will return before the new data has been loaded. Perform any post-processing
11645 * in a callback function, or in a "load" event handler.</strong>
11647 * @param {Object} options An object containing properties which control loading options:<ul>
11648 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11649 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11650 * passed the following arguments:<ul>
11651 * <li>r : Roo.data.Record[]</li>
11652 * <li>options: Options object from the load call</li>
11653 * <li>success: Boolean success indicator</li></ul></li>
11654 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11655 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11658 load : function(options){
11659 options = options || {};
11660 if(this.fireEvent("beforeload", this, options) !== false){
11661 this.storeOptions(options);
11662 var p = Roo.apply(options.params || {}, this.baseParams);
11663 // if meta was not loaded from remote source.. try requesting it.
11664 if (!this.reader.metaFromRemote) {
11665 p._requestMeta = 1;
11667 if(this.sortInfo && this.remoteSort){
11668 var pn = this.paramNames;
11669 p[pn["sort"]] = this.sortInfo.field;
11670 p[pn["dir"]] = this.sortInfo.direction;
11672 if (this.multiSort) {
11673 var pn = this.paramNames;
11674 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11677 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11682 * Reloads the Record cache from the configured Proxy using the configured Reader and
11683 * the options from the last load operation performed.
11684 * @param {Object} options (optional) An object containing properties which may override the options
11685 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11686 * the most recently used options are reused).
11688 reload : function(options){
11689 this.load(Roo.applyIf(options||{}, this.lastOptions));
11693 // Called as a callback by the Reader during a load operation.
11694 loadRecords : function(o, options, success){
11695 if(!o || success === false){
11696 if(success !== false){
11697 this.fireEvent("load", this, [], options, o);
11699 if(options.callback){
11700 options.callback.call(options.scope || this, [], options, false);
11704 // if data returned failure - throw an exception.
11705 if (o.success === false) {
11706 // show a message if no listener is registered.
11707 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11708 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11710 // loadmask wil be hooked into this..
11711 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11714 var r = o.records, t = o.totalRecords || r.length;
11716 this.fireEvent("beforeloadadd", this, r, options, o);
11718 if(!options || options.add !== true){
11719 if(this.pruneModifiedRecords){
11720 this.modified = [];
11722 for(var i = 0, len = r.length; i < len; i++){
11726 this.data = this.snapshot;
11727 delete this.snapshot;
11730 this.data.addAll(r);
11731 this.totalLength = t;
11733 this.fireEvent("datachanged", this);
11735 this.totalLength = Math.max(t, this.data.length+r.length);
11739 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11741 var e = new Roo.data.Record({});
11743 e.set(this.parent.displayField, this.parent.emptyTitle);
11744 e.set(this.parent.valueField, '');
11749 this.fireEvent("load", this, r, options, o);
11750 if(options.callback){
11751 options.callback.call(options.scope || this, r, options, true);
11757 * Loads data from a passed data block. A Reader which understands the format of the data
11758 * must have been configured in the constructor.
11759 * @param {Object} data The data block from which to read the Records. The format of the data expected
11760 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11761 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11763 loadData : function(o, append){
11764 var r = this.reader.readRecords(o);
11765 this.loadRecords(r, {add: append}, true);
11769 * Gets the number of cached records.
11771 * <em>If using paging, this may not be the total size of the dataset. If the data object
11772 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11773 * the data set size</em>
11775 getCount : function(){
11776 return this.data.length || 0;
11780 * Gets the total number of records in the dataset as returned by the server.
11782 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11783 * the dataset size</em>
11785 getTotalCount : function(){
11786 return this.totalLength || 0;
11790 * Returns the sort state of the Store as an object with two properties:
11792 field {String} The name of the field by which the Records are sorted
11793 direction {String} The sort order, "ASC" or "DESC"
11796 getSortState : function(){
11797 return this.sortInfo;
11801 applySort : function(){
11802 if(this.sortInfo && !this.remoteSort){
11803 var s = this.sortInfo, f = s.field;
11804 var st = this.fields.get(f).sortType;
11805 var fn = function(r1, r2){
11806 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11807 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11809 this.data.sort(s.direction, fn);
11810 if(this.snapshot && this.snapshot != this.data){
11811 this.snapshot.sort(s.direction, fn);
11817 * Sets the default sort column and order to be used by the next load operation.
11818 * @param {String} fieldName The name of the field to sort by.
11819 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11821 setDefaultSort : function(field, dir){
11822 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11826 * Sort the Records.
11827 * If remote sorting is used, the sort is performed on the server, and the cache is
11828 * reloaded. If local sorting is used, the cache is sorted internally.
11829 * @param {String} fieldName The name of the field to sort by.
11830 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11832 sort : function(fieldName, dir){
11833 var f = this.fields.get(fieldName);
11835 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11837 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11838 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11843 this.sortToggle[f.name] = dir;
11844 this.sortInfo = {field: f.name, direction: dir};
11845 if(!this.remoteSort){
11847 this.fireEvent("datachanged", this);
11849 this.load(this.lastOptions);
11854 * Calls the specified function for each of the Records in the cache.
11855 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11856 * Returning <em>false</em> aborts and exits the iteration.
11857 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11859 each : function(fn, scope){
11860 this.data.each(fn, scope);
11864 * Gets all records modified since the last commit. Modified records are persisted across load operations
11865 * (e.g., during paging).
11866 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11868 getModifiedRecords : function(){
11869 return this.modified;
11873 createFilterFn : function(property, value, anyMatch){
11874 if(!value.exec){ // not a regex
11875 value = String(value);
11876 if(value.length == 0){
11879 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11881 return function(r){
11882 return value.test(r.data[property]);
11887 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11888 * @param {String} property A field on your records
11889 * @param {Number} start The record index to start at (defaults to 0)
11890 * @param {Number} end The last record index to include (defaults to length - 1)
11891 * @return {Number} The sum
11893 sum : function(property, start, end){
11894 var rs = this.data.items, v = 0;
11895 start = start || 0;
11896 end = (end || end === 0) ? end : rs.length-1;
11898 for(var i = start; i <= end; i++){
11899 v += (rs[i].data[property] || 0);
11905 * Filter the records by a specified property.
11906 * @param {String} field A field on your records
11907 * @param {String/RegExp} value Either a string that the field
11908 * should start with or a RegExp to test against the field
11909 * @param {Boolean} anyMatch True to match any part not just the beginning
11911 filter : function(property, value, anyMatch){
11912 var fn = this.createFilterFn(property, value, anyMatch);
11913 return fn ? this.filterBy(fn) : this.clearFilter();
11917 * Filter by a function. The specified function will be called with each
11918 * record in this data source. If the function returns true the record is included,
11919 * otherwise it is filtered.
11920 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11921 * @param {Object} scope (optional) The scope of the function (defaults to this)
11923 filterBy : function(fn, scope){
11924 this.snapshot = this.snapshot || this.data;
11925 this.data = this.queryBy(fn, scope||this);
11926 this.fireEvent("datachanged", this);
11930 * Query the records by a specified property.
11931 * @param {String} field A field on your records
11932 * @param {String/RegExp} value Either a string that the field
11933 * should start with or a RegExp to test against the field
11934 * @param {Boolean} anyMatch True to match any part not just the beginning
11935 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11937 query : function(property, value, anyMatch){
11938 var fn = this.createFilterFn(property, value, anyMatch);
11939 return fn ? this.queryBy(fn) : this.data.clone();
11943 * Query by a function. The specified function will be called with each
11944 * record in this data source. If the function returns true the record is included
11946 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11947 * @param {Object} scope (optional) The scope of the function (defaults to this)
11948 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11950 queryBy : function(fn, scope){
11951 var data = this.snapshot || this.data;
11952 return data.filterBy(fn, scope||this);
11956 * Collects unique values for a particular dataIndex from this store.
11957 * @param {String} dataIndex The property to collect
11958 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11959 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11960 * @return {Array} An array of the unique values
11962 collect : function(dataIndex, allowNull, bypassFilter){
11963 var d = (bypassFilter === true && this.snapshot) ?
11964 this.snapshot.items : this.data.items;
11965 var v, sv, r = [], l = {};
11966 for(var i = 0, len = d.length; i < len; i++){
11967 v = d[i].data[dataIndex];
11969 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11978 * Revert to a view of the Record cache with no filtering applied.
11979 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11981 clearFilter : function(suppressEvent){
11982 if(this.snapshot && this.snapshot != this.data){
11983 this.data = this.snapshot;
11984 delete this.snapshot;
11985 if(suppressEvent !== true){
11986 this.fireEvent("datachanged", this);
11992 afterEdit : function(record){
11993 if(this.modified.indexOf(record) == -1){
11994 this.modified.push(record);
11996 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12000 afterReject : function(record){
12001 this.modified.remove(record);
12002 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12006 afterCommit : function(record){
12007 this.modified.remove(record);
12008 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12012 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12013 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12015 commitChanges : function(){
12016 var m = this.modified.slice(0);
12017 this.modified = [];
12018 for(var i = 0, len = m.length; i < len; i++){
12024 * Cancel outstanding changes on all changed records.
12026 rejectChanges : function(){
12027 var m = this.modified.slice(0);
12028 this.modified = [];
12029 for(var i = 0, len = m.length; i < len; i++){
12034 onMetaChange : function(meta, rtype, o){
12035 this.recordType = rtype;
12036 this.fields = rtype.prototype.fields;
12037 delete this.snapshot;
12038 this.sortInfo = meta.sortInfo || this.sortInfo;
12039 this.modified = [];
12040 this.fireEvent('metachange', this, this.reader.meta);
12043 moveIndex : function(data, type)
12045 var index = this.indexOf(data);
12047 var newIndex = index + type;
12051 this.insert(newIndex, data);
12056 * Ext JS Library 1.1.1
12057 * Copyright(c) 2006-2007, Ext JS, LLC.
12059 * Originally Released Under LGPL - original licence link has changed is not relivant.
12062 * <script type="text/javascript">
12066 * @class Roo.data.SimpleStore
12067 * @extends Roo.data.Store
12068 * Small helper class to make creating Stores from Array data easier.
12069 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12070 * @cfg {Array} fields An array of field definition objects, or field name strings.
12071 * @cfg {Array} data The multi-dimensional array of data
12073 * @param {Object} config
12075 Roo.data.SimpleStore = function(config){
12076 Roo.data.SimpleStore.superclass.constructor.call(this, {
12078 reader: new Roo.data.ArrayReader({
12081 Roo.data.Record.create(config.fields)
12083 proxy : new Roo.data.MemoryProxy(config.data)
12087 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12089 * Ext JS Library 1.1.1
12090 * Copyright(c) 2006-2007, Ext JS, LLC.
12092 * Originally Released Under LGPL - original licence link has changed is not relivant.
12095 * <script type="text/javascript">
12100 * @extends Roo.data.Store
12101 * @class Roo.data.JsonStore
12102 * Small helper class to make creating Stores for JSON data easier. <br/>
12104 var store = new Roo.data.JsonStore({
12105 url: 'get-images.php',
12107 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12110 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12111 * JsonReader and HttpProxy (unless inline data is provided).</b>
12112 * @cfg {Array} fields An array of field definition objects, or field name strings.
12114 * @param {Object} config
12116 Roo.data.JsonStore = function(c){
12117 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12118 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12119 reader: new Roo.data.JsonReader(c, c.fields)
12122 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12124 * Ext JS Library 1.1.1
12125 * Copyright(c) 2006-2007, Ext JS, LLC.
12127 * Originally Released Under LGPL - original licence link has changed is not relivant.
12130 * <script type="text/javascript">
12134 Roo.data.Field = function(config){
12135 if(typeof config == "string"){
12136 config = {name: config};
12138 Roo.apply(this, config);
12141 this.type = "auto";
12144 var st = Roo.data.SortTypes;
12145 // named sortTypes are supported, here we look them up
12146 if(typeof this.sortType == "string"){
12147 this.sortType = st[this.sortType];
12150 // set default sortType for strings and dates
12151 if(!this.sortType){
12154 this.sortType = st.asUCString;
12157 this.sortType = st.asDate;
12160 this.sortType = st.none;
12165 var stripRe = /[\$,%]/g;
12167 // prebuilt conversion function for this field, instead of
12168 // switching every time we're reading a value
12170 var cv, dateFormat = this.dateFormat;
12175 cv = function(v){ return v; };
12178 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12182 return v !== undefined && v !== null && v !== '' ?
12183 parseInt(String(v).replace(stripRe, ""), 10) : '';
12188 return v !== undefined && v !== null && v !== '' ?
12189 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12194 cv = function(v){ return v === true || v === "true" || v == 1; };
12201 if(v instanceof Date){
12205 if(dateFormat == "timestamp"){
12206 return new Date(v*1000);
12208 return Date.parseDate(v, dateFormat);
12210 var parsed = Date.parse(v);
12211 return parsed ? new Date(parsed) : null;
12220 Roo.data.Field.prototype = {
12228 * Ext JS Library 1.1.1
12229 * Copyright(c) 2006-2007, Ext JS, LLC.
12231 * Originally Released Under LGPL - original licence link has changed is not relivant.
12234 * <script type="text/javascript">
12237 // Base class for reading structured data from a data source. This class is intended to be
12238 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12241 * @class Roo.data.DataReader
12242 * Base class for reading structured data from a data source. This class is intended to be
12243 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12246 Roo.data.DataReader = function(meta, recordType){
12250 this.recordType = recordType instanceof Array ?
12251 Roo.data.Record.create(recordType) : recordType;
12254 Roo.data.DataReader.prototype = {
12256 * Create an empty record
12257 * @param {Object} data (optional) - overlay some values
12258 * @return {Roo.data.Record} record created.
12260 newRow : function(d) {
12262 this.recordType.prototype.fields.each(function(c) {
12264 case 'int' : da[c.name] = 0; break;
12265 case 'date' : da[c.name] = new Date(); break;
12266 case 'float' : da[c.name] = 0.0; break;
12267 case 'boolean' : da[c.name] = false; break;
12268 default : da[c.name] = ""; break;
12272 return new this.recordType(Roo.apply(da, d));
12277 * Ext JS Library 1.1.1
12278 * Copyright(c) 2006-2007, Ext JS, LLC.
12280 * Originally Released Under LGPL - original licence link has changed is not relivant.
12283 * <script type="text/javascript">
12287 * @class Roo.data.DataProxy
12288 * @extends Roo.data.Observable
12289 * This class is an abstract base class for implementations which provide retrieval of
12290 * unformatted data objects.<br>
12292 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12293 * (of the appropriate type which knows how to parse the data object) to provide a block of
12294 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12296 * Custom implementations must implement the load method as described in
12297 * {@link Roo.data.HttpProxy#load}.
12299 Roo.data.DataProxy = function(){
12302 * @event beforeload
12303 * Fires before a network request is made to retrieve a data object.
12304 * @param {Object} This DataProxy object.
12305 * @param {Object} params The params parameter to the load function.
12310 * Fires before the load method's callback is called.
12311 * @param {Object} This DataProxy object.
12312 * @param {Object} o The data object.
12313 * @param {Object} arg The callback argument object passed to the load function.
12317 * @event loadexception
12318 * Fires if an Exception occurs during data retrieval.
12319 * @param {Object} This DataProxy object.
12320 * @param {Object} o The data object.
12321 * @param {Object} arg The callback argument object passed to the load function.
12322 * @param {Object} e The Exception.
12324 loadexception : true
12326 Roo.data.DataProxy.superclass.constructor.call(this);
12329 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12332 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12336 * Ext JS Library 1.1.1
12337 * Copyright(c) 2006-2007, Ext JS, LLC.
12339 * Originally Released Under LGPL - original licence link has changed is not relivant.
12342 * <script type="text/javascript">
12345 * @class Roo.data.MemoryProxy
12346 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12347 * to the Reader when its load method is called.
12349 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12351 Roo.data.MemoryProxy = function(data){
12355 Roo.data.MemoryProxy.superclass.constructor.call(this);
12359 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12362 * Load data from the requested source (in this case an in-memory
12363 * data object passed to the constructor), read the data object into
12364 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12365 * process that block using the passed callback.
12366 * @param {Object} params This parameter is not used by the MemoryProxy class.
12367 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12368 * object into a block of Roo.data.Records.
12369 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12370 * The function must be passed <ul>
12371 * <li>The Record block object</li>
12372 * <li>The "arg" argument from the load function</li>
12373 * <li>A boolean success indicator</li>
12375 * @param {Object} scope The scope in which to call the callback
12376 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12378 load : function(params, reader, callback, scope, arg){
12379 params = params || {};
12382 result = reader.readRecords(params.data ? params.data :this.data);
12384 this.fireEvent("loadexception", this, arg, null, e);
12385 callback.call(scope, null, arg, false);
12388 callback.call(scope, result, arg, true);
12392 update : function(params, records){
12397 * Ext JS Library 1.1.1
12398 * Copyright(c) 2006-2007, Ext JS, LLC.
12400 * Originally Released Under LGPL - original licence link has changed is not relivant.
12403 * <script type="text/javascript">
12406 * @class Roo.data.HttpProxy
12407 * @extends Roo.data.DataProxy
12408 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12409 * configured to reference a certain URL.<br><br>
12411 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12412 * from which the running page was served.<br><br>
12414 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12416 * Be aware that to enable the browser to parse an XML document, the server must set
12417 * the Content-Type header in the HTTP response to "text/xml".
12419 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12420 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12421 * will be used to make the request.
12423 Roo.data.HttpProxy = function(conn){
12424 Roo.data.HttpProxy.superclass.constructor.call(this);
12425 // is conn a conn config or a real conn?
12427 this.useAjax = !conn || !conn.events;
12431 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12432 // thse are take from connection...
12435 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12438 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12439 * extra parameters to each request made by this object. (defaults to undefined)
12442 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12443 * to each request made by this object. (defaults to undefined)
12446 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
12449 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12452 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12458 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12462 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12463 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12464 * a finer-grained basis than the DataProxy events.
12466 getConnection : function(){
12467 return this.useAjax ? Roo.Ajax : this.conn;
12471 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12472 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12473 * process that block using the passed callback.
12474 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12475 * for the request to the remote server.
12476 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12477 * object into a block of Roo.data.Records.
12478 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12479 * The function must be passed <ul>
12480 * <li>The Record block object</li>
12481 * <li>The "arg" argument from the load function</li>
12482 * <li>A boolean success indicator</li>
12484 * @param {Object} scope The scope in which to call the callback
12485 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12487 load : function(params, reader, callback, scope, arg){
12488 if(this.fireEvent("beforeload", this, params) !== false){
12490 params : params || {},
12492 callback : callback,
12497 callback : this.loadResponse,
12501 Roo.applyIf(o, this.conn);
12502 if(this.activeRequest){
12503 Roo.Ajax.abort(this.activeRequest);
12505 this.activeRequest = Roo.Ajax.request(o);
12507 this.conn.request(o);
12510 callback.call(scope||this, null, arg, false);
12515 loadResponse : function(o, success, response){
12516 delete this.activeRequest;
12518 this.fireEvent("loadexception", this, o, response);
12519 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12524 result = o.reader.read(response);
12526 this.fireEvent("loadexception", this, o, response, e);
12527 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12531 this.fireEvent("load", this, o, o.request.arg);
12532 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12536 update : function(dataSet){
12541 updateResponse : function(dataSet){
12546 * Ext JS Library 1.1.1
12547 * Copyright(c) 2006-2007, Ext JS, LLC.
12549 * Originally Released Under LGPL - original licence link has changed is not relivant.
12552 * <script type="text/javascript">
12556 * @class Roo.data.ScriptTagProxy
12557 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12558 * other than the originating domain of the running page.<br><br>
12560 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
12561 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12563 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12564 * source code that is used as the source inside a <script> tag.<br><br>
12566 * In order for the browser to process the returned data, the server must wrap the data object
12567 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12568 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12569 * depending on whether the callback name was passed:
12572 boolean scriptTag = false;
12573 String cb = request.getParameter("callback");
12576 response.setContentType("text/javascript");
12578 response.setContentType("application/x-json");
12580 Writer out = response.getWriter();
12582 out.write(cb + "(");
12584 out.print(dataBlock.toJsonString());
12591 * @param {Object} config A configuration object.
12593 Roo.data.ScriptTagProxy = function(config){
12594 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12595 Roo.apply(this, config);
12596 this.head = document.getElementsByTagName("head")[0];
12599 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12601 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12603 * @cfg {String} url The URL from which to request the data object.
12606 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12610 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12611 * the server the name of the callback function set up by the load call to process the returned data object.
12612 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12613 * javascript output which calls this named function passing the data object as its only parameter.
12615 callbackParam : "callback",
12617 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12618 * name to the request.
12623 * Load data from the configured URL, read the data object into
12624 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12625 * process that block using the passed callback.
12626 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12627 * for the request to the remote server.
12628 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12629 * object into a block of Roo.data.Records.
12630 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12631 * The function must be passed <ul>
12632 * <li>The Record block object</li>
12633 * <li>The "arg" argument from the load function</li>
12634 * <li>A boolean success indicator</li>
12636 * @param {Object} scope The scope in which to call the callback
12637 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12639 load : function(params, reader, callback, scope, arg){
12640 if(this.fireEvent("beforeload", this, params) !== false){
12642 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12644 var url = this.url;
12645 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12647 url += "&_dc=" + (new Date().getTime());
12649 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12652 cb : "stcCallback"+transId,
12653 scriptId : "stcScript"+transId,
12657 callback : callback,
12663 window[trans.cb] = function(o){
12664 conn.handleResponse(o, trans);
12667 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12669 if(this.autoAbort !== false){
12673 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12675 var script = document.createElement("script");
12676 script.setAttribute("src", url);
12677 script.setAttribute("type", "text/javascript");
12678 script.setAttribute("id", trans.scriptId);
12679 this.head.appendChild(script);
12681 this.trans = trans;
12683 callback.call(scope||this, null, arg, false);
12688 isLoading : function(){
12689 return this.trans ? true : false;
12693 * Abort the current server request.
12695 abort : function(){
12696 if(this.isLoading()){
12697 this.destroyTrans(this.trans);
12702 destroyTrans : function(trans, isLoaded){
12703 this.head.removeChild(document.getElementById(trans.scriptId));
12704 clearTimeout(trans.timeoutId);
12706 window[trans.cb] = undefined;
12708 delete window[trans.cb];
12711 // if hasn't been loaded, wait for load to remove it to prevent script error
12712 window[trans.cb] = function(){
12713 window[trans.cb] = undefined;
12715 delete window[trans.cb];
12722 handleResponse : function(o, trans){
12723 this.trans = false;
12724 this.destroyTrans(trans, true);
12727 result = trans.reader.readRecords(o);
12729 this.fireEvent("loadexception", this, o, trans.arg, e);
12730 trans.callback.call(trans.scope||window, null, trans.arg, false);
12733 this.fireEvent("load", this, o, trans.arg);
12734 trans.callback.call(trans.scope||window, result, trans.arg, true);
12738 handleFailure : function(trans){
12739 this.trans = false;
12740 this.destroyTrans(trans, false);
12741 this.fireEvent("loadexception", this, null, trans.arg);
12742 trans.callback.call(trans.scope||window, null, trans.arg, false);
12746 * Ext JS Library 1.1.1
12747 * Copyright(c) 2006-2007, Ext JS, LLC.
12749 * Originally Released Under LGPL - original licence link has changed is not relivant.
12752 * <script type="text/javascript">
12756 * @class Roo.data.JsonReader
12757 * @extends Roo.data.DataReader
12758 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12759 * based on mappings in a provided Roo.data.Record constructor.
12761 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12762 * in the reply previously.
12767 var RecordDef = Roo.data.Record.create([
12768 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12769 {name: 'occupation'} // This field will use "occupation" as the mapping.
12771 var myReader = new Roo.data.JsonReader({
12772 totalProperty: "results", // The property which contains the total dataset size (optional)
12773 root: "rows", // The property which contains an Array of row objects
12774 id: "id" // The property within each row object that provides an ID for the record (optional)
12778 * This would consume a JSON file like this:
12780 { 'results': 2, 'rows': [
12781 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12782 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12785 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12786 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12787 * paged from the remote server.
12788 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12789 * @cfg {String} root name of the property which contains the Array of row objects.
12790 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12791 * @cfg {Array} fields Array of field definition objects
12793 * Create a new JsonReader
12794 * @param {Object} meta Metadata configuration options
12795 * @param {Object} recordType Either an Array of field definition objects,
12796 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12798 Roo.data.JsonReader = function(meta, recordType){
12801 // set some defaults:
12802 Roo.applyIf(meta, {
12803 totalProperty: 'total',
12804 successProperty : 'success',
12809 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12811 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12814 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12815 * Used by Store query builder to append _requestMeta to params.
12818 metaFromRemote : false,
12820 * This method is only used by a DataProxy which has retrieved data from a remote server.
12821 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12822 * @return {Object} data A data block which is used by an Roo.data.Store object as
12823 * a cache of Roo.data.Records.
12825 read : function(response){
12826 var json = response.responseText;
12828 var o = /* eval:var:o */ eval("("+json+")");
12830 throw {message: "JsonReader.read: Json object not found"};
12836 this.metaFromRemote = true;
12837 this.meta = o.metaData;
12838 this.recordType = Roo.data.Record.create(o.metaData.fields);
12839 this.onMetaChange(this.meta, this.recordType, o);
12841 return this.readRecords(o);
12844 // private function a store will implement
12845 onMetaChange : function(meta, recordType, o){
12852 simpleAccess: function(obj, subsc) {
12859 getJsonAccessor: function(){
12861 return function(expr) {
12863 return(re.test(expr))
12864 ? new Function("obj", "return obj." + expr)
12869 return Roo.emptyFn;
12874 * Create a data block containing Roo.data.Records from an XML document.
12875 * @param {Object} o An object which contains an Array of row objects in the property specified
12876 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12877 * which contains the total size of the dataset.
12878 * @return {Object} data A data block which is used by an Roo.data.Store object as
12879 * a cache of Roo.data.Records.
12881 readRecords : function(o){
12883 * After any data loads, the raw JSON data is available for further custom processing.
12887 var s = this.meta, Record = this.recordType,
12888 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12890 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12892 if(s.totalProperty) {
12893 this.getTotal = this.getJsonAccessor(s.totalProperty);
12895 if(s.successProperty) {
12896 this.getSuccess = this.getJsonAccessor(s.successProperty);
12898 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12900 var g = this.getJsonAccessor(s.id);
12901 this.getId = function(rec) {
12903 return (r === undefined || r === "") ? null : r;
12906 this.getId = function(){return null;};
12909 for(var jj = 0; jj < fl; jj++){
12911 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12912 this.ef[jj] = this.getJsonAccessor(map);
12916 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12917 if(s.totalProperty){
12918 var vt = parseInt(this.getTotal(o), 10);
12923 if(s.successProperty){
12924 var vs = this.getSuccess(o);
12925 if(vs === false || vs === 'false'){
12930 for(var i = 0; i < c; i++){
12933 var id = this.getId(n);
12934 for(var j = 0; j < fl; j++){
12936 var v = this.ef[j](n);
12938 Roo.log('missing convert for ' + f.name);
12942 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12944 var record = new Record(values, id);
12946 records[i] = record;
12952 totalRecords : totalRecords
12957 * Ext JS Library 1.1.1
12958 * Copyright(c) 2006-2007, Ext JS, LLC.
12960 * Originally Released Under LGPL - original licence link has changed is not relivant.
12963 * <script type="text/javascript">
12967 * @class Roo.data.ArrayReader
12968 * @extends Roo.data.DataReader
12969 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12970 * Each element of that Array represents a row of data fields. The
12971 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12972 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12976 var RecordDef = Roo.data.Record.create([
12977 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12978 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12980 var myReader = new Roo.data.ArrayReader({
12981 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12985 * This would consume an Array like this:
12987 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12989 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12991 * Create a new JsonReader
12992 * @param {Object} meta Metadata configuration options.
12993 * @param {Object} recordType Either an Array of field definition objects
12994 * @cfg {Array} fields Array of field definition objects
12995 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12996 * as specified to {@link Roo.data.Record#create},
12997 * or an {@link Roo.data.Record} object
12998 * created using {@link Roo.data.Record#create}.
13000 Roo.data.ArrayReader = function(meta, recordType){
13003 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13006 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13008 * Create a data block containing Roo.data.Records from an XML document.
13009 * @param {Object} o An Array of row objects which represents the dataset.
13010 * @return {Object} data A data block which is used by an Roo.data.Store object as
13011 * a cache of Roo.data.Records.
13013 readRecords : function(o){
13014 var sid = this.meta ? this.meta.id : null;
13015 var recordType = this.recordType, fields = recordType.prototype.fields;
13018 for(var i = 0; i < root.length; i++){
13021 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13022 for(var j = 0, jlen = fields.length; j < jlen; j++){
13023 var f = fields.items[j];
13024 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13025 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13027 values[f.name] = v;
13029 var record = new recordType(values, id);
13031 records[records.length] = record;
13035 totalRecords : records.length
13044 * @class Roo.bootstrap.ComboBox
13045 * @extends Roo.bootstrap.TriggerField
13046 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13047 * @cfg {Boolean} append (true|false) default false
13048 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13049 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13050 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13051 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13052 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13053 * @cfg {Boolean} animate default true
13054 * @cfg {Boolean} emptyResultText only for touch device
13055 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13056 * @cfg {String} emptyTitle default ''
13058 * Create a new ComboBox.
13059 * @param {Object} config Configuration options
13061 Roo.bootstrap.ComboBox = function(config){
13062 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13066 * Fires when the dropdown list is expanded
13067 * @param {Roo.bootstrap.ComboBox} combo This combo box
13072 * Fires when the dropdown list is collapsed
13073 * @param {Roo.bootstrap.ComboBox} combo This combo box
13077 * @event beforeselect
13078 * Fires before a list item is selected. Return false to cancel the selection.
13079 * @param {Roo.bootstrap.ComboBox} combo This combo box
13080 * @param {Roo.data.Record} record The data record returned from the underlying store
13081 * @param {Number} index The index of the selected item in the dropdown list
13083 'beforeselect' : true,
13086 * Fires when a list item is selected
13087 * @param {Roo.bootstrap.ComboBox} combo This combo box
13088 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13089 * @param {Number} index The index of the selected item in the dropdown list
13093 * @event beforequery
13094 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13095 * The event object passed has these properties:
13096 * @param {Roo.bootstrap.ComboBox} combo This combo box
13097 * @param {String} query The query
13098 * @param {Boolean} forceAll true to force "all" query
13099 * @param {Boolean} cancel true to cancel the query
13100 * @param {Object} e The query event object
13102 'beforequery': true,
13105 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13106 * @param {Roo.bootstrap.ComboBox} combo This combo box
13111 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13112 * @param {Roo.bootstrap.ComboBox} combo This combo box
13113 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13118 * Fires when the remove value from the combobox array
13119 * @param {Roo.bootstrap.ComboBox} combo This combo box
13123 * @event afterremove
13124 * Fires when the remove value from the combobox array
13125 * @param {Roo.bootstrap.ComboBox} combo This combo box
13127 'afterremove' : true,
13129 * @event specialfilter
13130 * Fires when specialfilter
13131 * @param {Roo.bootstrap.ComboBox} combo This combo box
13133 'specialfilter' : true,
13136 * Fires when tick the element
13137 * @param {Roo.bootstrap.ComboBox} combo This combo box
13141 * @event touchviewdisplay
13142 * Fires when touch view require special display (default is using displayField)
13143 * @param {Roo.bootstrap.ComboBox} combo This combo box
13144 * @param {Object} cfg set html .
13146 'touchviewdisplay' : true
13151 this.tickItems = [];
13153 this.selectedIndex = -1;
13154 if(this.mode == 'local'){
13155 if(config.queryDelay === undefined){
13156 this.queryDelay = 10;
13158 if(config.minChars === undefined){
13164 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13167 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13168 * rendering into an Roo.Editor, defaults to false)
13171 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13172 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13175 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13178 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13179 * the dropdown list (defaults to undefined, with no header element)
13183 * @cfg {String/Roo.Template} tpl The template to use to render the output
13187 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13189 listWidth: undefined,
13191 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13192 * mode = 'remote' or 'text' if mode = 'local')
13194 displayField: undefined,
13197 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13198 * mode = 'remote' or 'value' if mode = 'local').
13199 * Note: use of a valueField requires the user make a selection
13200 * in order for a value to be mapped.
13202 valueField: undefined,
13204 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13209 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13210 * field's data value (defaults to the underlying DOM element's name)
13212 hiddenName: undefined,
13214 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13218 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13220 selectedClass: 'active',
13223 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13227 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13228 * anchor positions (defaults to 'tl-bl')
13230 listAlign: 'tl-bl?',
13232 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13236 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13237 * query specified by the allQuery config option (defaults to 'query')
13239 triggerAction: 'query',
13241 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13242 * (defaults to 4, does not apply if editable = false)
13246 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13247 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13251 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13252 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13256 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13257 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13261 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13262 * when editable = true (defaults to false)
13264 selectOnFocus:false,
13266 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13268 queryParam: 'query',
13270 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13271 * when mode = 'remote' (defaults to 'Loading...')
13273 loadingText: 'Loading...',
13275 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13279 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13283 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13284 * traditional select (defaults to true)
13288 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13292 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13296 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13297 * listWidth has a higher value)
13301 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13302 * allow the user to set arbitrary text into the field (defaults to false)
13304 forceSelection:false,
13306 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13307 * if typeAhead = true (defaults to 250)
13309 typeAheadDelay : 250,
13311 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13312 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13314 valueNotFoundText : undefined,
13316 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13318 blockFocus : false,
13321 * @cfg {Boolean} disableClear Disable showing of clear button.
13323 disableClear : false,
13325 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13327 alwaysQuery : false,
13330 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13335 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13337 invalidClass : "has-warning",
13340 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13342 validClass : "has-success",
13345 * @cfg {Boolean} specialFilter (true|false) special filter default false
13347 specialFilter : false,
13350 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13352 mobileTouchView : true,
13355 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13357 useNativeIOS : false,
13360 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13362 mobile_restrict_height : false,
13364 ios_options : false,
13376 btnPosition : 'right',
13377 triggerList : true,
13378 showToggleBtn : true,
13380 emptyResultText: 'Empty',
13381 triggerText : 'Select',
13384 // element that contains real text value.. (when hidden is used..)
13386 getAutoCreate : function()
13391 * Render classic select for iso
13394 if(Roo.isIOS && this.useNativeIOS){
13395 cfg = this.getAutoCreateNativeIOS();
13403 if(Roo.isTouch && this.mobileTouchView){
13404 cfg = this.getAutoCreateTouchView();
13411 if(!this.tickable){
13412 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13417 * ComboBox with tickable selections
13420 var align = this.labelAlign || this.parentLabelAlign();
13423 cls : 'form-group roo-combobox-tickable' //input-group
13426 var btn_text_select = '';
13427 var btn_text_done = '';
13428 var btn_text_cancel = '';
13430 if (this.btn_text_show) {
13431 btn_text_select = 'Select';
13432 btn_text_done = 'Done';
13433 btn_text_cancel = 'Cancel';
13438 cls : 'tickable-buttons',
13443 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13444 //html : this.triggerText
13445 html: btn_text_select
13451 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13453 html: btn_text_done
13459 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13461 html: btn_text_cancel
13467 buttons.cn.unshift({
13469 cls: 'roo-select2-search-field-input'
13475 Roo.each(buttons.cn, function(c){
13477 c.cls += ' btn-' + _this.size;
13480 if (_this.disabled) {
13487 style : 'display: contents',
13492 cls: 'form-hidden-field'
13496 cls: 'roo-select2-choices',
13500 cls: 'roo-select2-search-field',
13511 cls: 'roo-select2-container input-group roo-select2-container-multi',
13517 // cls: 'typeahead typeahead-long dropdown-menu',
13518 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13523 if(this.hasFeedback && !this.allowBlank){
13527 cls: 'glyphicon form-control-feedback'
13530 combobox.cn.push(feedback);
13535 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13536 tooltip : 'This field is required'
13538 if (Roo.bootstrap.version == 4) {
13541 style : 'display:none'
13544 if (align ==='left' && this.fieldLabel.length) {
13546 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13553 cls : 'control-label col-form-label',
13554 html : this.fieldLabel
13566 var labelCfg = cfg.cn[1];
13567 var contentCfg = cfg.cn[2];
13570 if(this.indicatorpos == 'right'){
13576 cls : 'control-label col-form-label',
13580 html : this.fieldLabel
13596 labelCfg = cfg.cn[0];
13597 contentCfg = cfg.cn[1];
13601 if(this.labelWidth > 12){
13602 labelCfg.style = "width: " + this.labelWidth + 'px';
13605 if(this.labelWidth < 13 && this.labelmd == 0){
13606 this.labelmd = this.labelWidth;
13609 if(this.labellg > 0){
13610 labelCfg.cls += ' col-lg-' + this.labellg;
13611 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13614 if(this.labelmd > 0){
13615 labelCfg.cls += ' col-md-' + this.labelmd;
13616 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13619 if(this.labelsm > 0){
13620 labelCfg.cls += ' col-sm-' + this.labelsm;
13621 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13624 if(this.labelxs > 0){
13625 labelCfg.cls += ' col-xs-' + this.labelxs;
13626 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13630 } else if ( this.fieldLabel.length) {
13631 // Roo.log(" label");
13636 //cls : 'input-group-addon',
13637 html : this.fieldLabel
13642 if(this.indicatorpos == 'right'){
13646 //cls : 'input-group-addon',
13647 html : this.fieldLabel
13657 // Roo.log(" no label && no align");
13664 ['xs','sm','md','lg'].map(function(size){
13665 if (settings[size]) {
13666 cfg.cls += ' col-' + size + '-' + settings[size];
13674 _initEventsCalled : false,
13677 initEvents: function()
13679 if (this._initEventsCalled) { // as we call render... prevent looping...
13682 this._initEventsCalled = true;
13685 throw "can not find store for combo";
13688 this.indicator = this.indicatorEl();
13690 this.store = Roo.factory(this.store, Roo.data);
13691 this.store.parent = this;
13693 // if we are building from html. then this element is so complex, that we can not really
13694 // use the rendered HTML.
13695 // so we have to trash and replace the previous code.
13696 if (Roo.XComponent.build_from_html) {
13697 // remove this element....
13698 var e = this.el.dom, k=0;
13699 while (e ) { e = e.previousSibling; ++k;}
13704 this.rendered = false;
13706 this.render(this.parent().getChildContainer(true), k);
13709 if(Roo.isIOS && this.useNativeIOS){
13710 this.initIOSView();
13718 if(Roo.isTouch && this.mobileTouchView){
13719 this.initTouchView();
13724 this.initTickableEvents();
13728 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13730 if(this.hiddenName){
13732 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13734 this.hiddenField.dom.value =
13735 this.hiddenValue !== undefined ? this.hiddenValue :
13736 this.value !== undefined ? this.value : '';
13738 // prevent input submission
13739 this.el.dom.removeAttribute('name');
13740 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13745 // this.el.dom.setAttribute('autocomplete', 'off');
13748 var cls = 'x-combo-list';
13750 //this.list = new Roo.Layer({
13751 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13757 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13758 _this.list.setWidth(lw);
13761 this.list.on('mouseover', this.onViewOver, this);
13762 this.list.on('mousemove', this.onViewMove, this);
13763 this.list.on('scroll', this.onViewScroll, this);
13766 this.list.swallowEvent('mousewheel');
13767 this.assetHeight = 0;
13770 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13771 this.assetHeight += this.header.getHeight();
13774 this.innerList = this.list.createChild({cls:cls+'-inner'});
13775 this.innerList.on('mouseover', this.onViewOver, this);
13776 this.innerList.on('mousemove', this.onViewMove, this);
13777 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13779 if(this.allowBlank && !this.pageSize && !this.disableClear){
13780 this.footer = this.list.createChild({cls:cls+'-ft'});
13781 this.pageTb = new Roo.Toolbar(this.footer);
13785 this.footer = this.list.createChild({cls:cls+'-ft'});
13786 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13787 {pageSize: this.pageSize});
13791 if (this.pageTb && this.allowBlank && !this.disableClear) {
13793 this.pageTb.add(new Roo.Toolbar.Fill(), {
13794 cls: 'x-btn-icon x-btn-clear',
13796 handler: function()
13799 _this.clearValue();
13800 _this.onSelect(false, -1);
13805 this.assetHeight += this.footer.getHeight();
13810 this.tpl = Roo.bootstrap.version == 4 ?
13811 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13812 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13815 this.view = new Roo.View(this.list, this.tpl, {
13816 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13818 //this.view.wrapEl.setDisplayed(false);
13819 this.view.on('click', this.onViewClick, this);
13822 this.store.on('beforeload', this.onBeforeLoad, this);
13823 this.store.on('load', this.onLoad, this);
13824 this.store.on('loadexception', this.onLoadException, this);
13826 if(this.resizable){
13827 this.resizer = new Roo.Resizable(this.list, {
13828 pinned:true, handles:'se'
13830 this.resizer.on('resize', function(r, w, h){
13831 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13832 this.listWidth = w;
13833 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13834 this.restrictHeight();
13836 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13839 if(!this.editable){
13840 this.editable = true;
13841 this.setEditable(false);
13846 if (typeof(this.events.add.listeners) != 'undefined') {
13848 this.addicon = this.wrap.createChild(
13849 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13851 this.addicon.on('click', function(e) {
13852 this.fireEvent('add', this);
13855 if (typeof(this.events.edit.listeners) != 'undefined') {
13857 this.editicon = this.wrap.createChild(
13858 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13859 if (this.addicon) {
13860 this.editicon.setStyle('margin-left', '40px');
13862 this.editicon.on('click', function(e) {
13864 // we fire even if inothing is selected..
13865 this.fireEvent('edit', this, this.lastData );
13871 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13872 "up" : function(e){
13873 this.inKeyMode = true;
13877 "down" : function(e){
13878 if(!this.isExpanded()){
13879 this.onTriggerClick();
13881 this.inKeyMode = true;
13886 "enter" : function(e){
13887 // this.onViewClick();
13891 if(this.fireEvent("specialkey", this, e)){
13892 this.onViewClick(false);
13898 "esc" : function(e){
13902 "tab" : function(e){
13905 if(this.fireEvent("specialkey", this, e)){
13906 this.onViewClick(false);
13914 doRelay : function(foo, bar, hname){
13915 if(hname == 'down' || this.scope.isExpanded()){
13916 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13925 this.queryDelay = Math.max(this.queryDelay || 10,
13926 this.mode == 'local' ? 10 : 250);
13929 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13931 if(this.typeAhead){
13932 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13934 if(this.editable !== false){
13935 this.inputEl().on("keyup", this.onKeyUp, this);
13937 if(this.forceSelection){
13938 this.inputEl().on('blur', this.doForce, this);
13942 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13943 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13947 initTickableEvents: function()
13951 if(this.hiddenName){
13953 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13955 this.hiddenField.dom.value =
13956 this.hiddenValue !== undefined ? this.hiddenValue :
13957 this.value !== undefined ? this.value : '';
13959 // prevent input submission
13960 this.el.dom.removeAttribute('name');
13961 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13966 // this.list = this.el.select('ul.dropdown-menu',true).first();
13968 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13969 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13970 if(this.triggerList){
13971 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13974 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13975 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13977 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13978 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13980 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13981 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13983 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13984 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13985 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13988 this.cancelBtn.hide();
13993 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13994 _this.list.setWidth(lw);
13997 this.list.on('mouseover', this.onViewOver, this);
13998 this.list.on('mousemove', this.onViewMove, this);
14000 this.list.on('scroll', this.onViewScroll, this);
14003 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14004 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14007 this.view = new Roo.View(this.list, this.tpl, {
14012 selectedClass: this.selectedClass
14015 //this.view.wrapEl.setDisplayed(false);
14016 this.view.on('click', this.onViewClick, this);
14020 this.store.on('beforeload', this.onBeforeLoad, this);
14021 this.store.on('load', this.onLoad, this);
14022 this.store.on('loadexception', this.onLoadException, this);
14025 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14026 "up" : function(e){
14027 this.inKeyMode = true;
14031 "down" : function(e){
14032 this.inKeyMode = true;
14036 "enter" : function(e){
14037 if(this.fireEvent("specialkey", this, e)){
14038 this.onViewClick(false);
14044 "esc" : function(e){
14045 this.onTickableFooterButtonClick(e, false, false);
14048 "tab" : function(e){
14049 this.fireEvent("specialkey", this, e);
14051 this.onTickableFooterButtonClick(e, false, false);
14058 doRelay : function(e, fn, key){
14059 if(this.scope.isExpanded()){
14060 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14069 this.queryDelay = Math.max(this.queryDelay || 10,
14070 this.mode == 'local' ? 10 : 250);
14073 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14075 if(this.typeAhead){
14076 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14079 if(this.editable !== false){
14080 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14083 this.indicator = this.indicatorEl();
14085 if(this.indicator){
14086 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14087 this.indicator.hide();
14092 onDestroy : function(){
14094 this.view.setStore(null);
14095 this.view.el.removeAllListeners();
14096 this.view.el.remove();
14097 this.view.purgeListeners();
14100 this.list.dom.innerHTML = '';
14104 this.store.un('beforeload', this.onBeforeLoad, this);
14105 this.store.un('load', this.onLoad, this);
14106 this.store.un('loadexception', this.onLoadException, this);
14108 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14112 fireKey : function(e){
14113 if(e.isNavKeyPress() && !this.list.isVisible()){
14114 this.fireEvent("specialkey", this, e);
14119 onResize: function(w, h){
14120 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14122 // if(typeof w != 'number'){
14123 // // we do not handle it!?!?
14126 // var tw = this.trigger.getWidth();
14127 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14128 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14130 // this.inputEl().setWidth( this.adjustWidth('input', x));
14132 // //this.trigger.setStyle('left', x+'px');
14134 // if(this.list && this.listWidth === undefined){
14135 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14136 // this.list.setWidth(lw);
14137 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14145 * Allow or prevent the user from directly editing the field text. If false is passed,
14146 * the user will only be able to select from the items defined in the dropdown list. This method
14147 * is the runtime equivalent of setting the 'editable' config option at config time.
14148 * @param {Boolean} value True to allow the user to directly edit the field text
14150 setEditable : function(value){
14151 if(value == this.editable){
14154 this.editable = value;
14156 this.inputEl().dom.setAttribute('readOnly', true);
14157 this.inputEl().on('mousedown', this.onTriggerClick, this);
14158 this.inputEl().addClass('x-combo-noedit');
14160 this.inputEl().dom.setAttribute('readOnly', false);
14161 this.inputEl().un('mousedown', this.onTriggerClick, this);
14162 this.inputEl().removeClass('x-combo-noedit');
14168 onBeforeLoad : function(combo,opts){
14169 if(!this.hasFocus){
14173 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14175 this.restrictHeight();
14176 this.selectedIndex = -1;
14180 onLoad : function(){
14182 this.hasQuery = false;
14184 if(!this.hasFocus){
14188 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14189 this.loading.hide();
14192 if(this.store.getCount() > 0){
14195 this.restrictHeight();
14196 if(this.lastQuery == this.allQuery){
14197 if(this.editable && !this.tickable){
14198 this.inputEl().dom.select();
14202 !this.selectByValue(this.value, true) &&
14205 !this.store.lastOptions ||
14206 typeof(this.store.lastOptions.add) == 'undefined' ||
14207 this.store.lastOptions.add != true
14210 this.select(0, true);
14213 if(this.autoFocus){
14216 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14217 this.taTask.delay(this.typeAheadDelay);
14221 this.onEmptyResults();
14227 onLoadException : function()
14229 this.hasQuery = false;
14231 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14232 this.loading.hide();
14235 if(this.tickable && this.editable){
14240 // only causes errors at present
14241 //Roo.log(this.store.reader.jsonData);
14242 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14244 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14250 onTypeAhead : function(){
14251 if(this.store.getCount() > 0){
14252 var r = this.store.getAt(0);
14253 var newValue = r.data[this.displayField];
14254 var len = newValue.length;
14255 var selStart = this.getRawValue().length;
14257 if(selStart != len){
14258 this.setRawValue(newValue);
14259 this.selectText(selStart, newValue.length);
14265 onSelect : function(record, index){
14267 if(this.fireEvent('beforeselect', this, record, index) !== false){
14269 this.setFromData(index > -1 ? record.data : false);
14272 this.fireEvent('select', this, record, index);
14277 * Returns the currently selected field value or empty string if no value is set.
14278 * @return {String} value The selected value
14280 getValue : function()
14282 if(Roo.isIOS && this.useNativeIOS){
14283 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14287 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14290 if(this.valueField){
14291 return typeof this.value != 'undefined' ? this.value : '';
14293 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14297 getRawValue : function()
14299 if(Roo.isIOS && this.useNativeIOS){
14300 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14303 var v = this.inputEl().getValue();
14309 * Clears any text/value currently set in the field
14311 clearValue : function(){
14313 if(this.hiddenField){
14314 this.hiddenField.dom.value = '';
14317 this.setRawValue('');
14318 this.lastSelectionText = '';
14319 this.lastData = false;
14321 var close = this.closeTriggerEl();
14332 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14333 * will be displayed in the field. If the value does not match the data value of an existing item,
14334 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14335 * Otherwise the field will be blank (although the value will still be set).
14336 * @param {String} value The value to match
14338 setValue : function(v)
14340 if(Roo.isIOS && this.useNativeIOS){
14341 this.setIOSValue(v);
14351 if(this.valueField){
14352 var r = this.findRecord(this.valueField, v);
14354 text = r.data[this.displayField];
14355 }else if(this.valueNotFoundText !== undefined){
14356 text = this.valueNotFoundText;
14359 this.lastSelectionText = text;
14360 if(this.hiddenField){
14361 this.hiddenField.dom.value = v;
14363 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14366 var close = this.closeTriggerEl();
14369 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14375 * @property {Object} the last set data for the element
14380 * Sets the value of the field based on a object which is related to the record format for the store.
14381 * @param {Object} value the value to set as. or false on reset?
14383 setFromData : function(o){
14390 var dv = ''; // display value
14391 var vv = ''; // value value..
14393 if (this.displayField) {
14394 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14396 // this is an error condition!!!
14397 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14400 if(this.valueField){
14401 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14404 var close = this.closeTriggerEl();
14407 if(dv.length || vv * 1 > 0){
14409 this.blockFocus=true;
14415 if(this.hiddenField){
14416 this.hiddenField.dom.value = vv;
14418 this.lastSelectionText = dv;
14419 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14423 // no hidden field.. - we store the value in 'value', but still display
14424 // display field!!!!
14425 this.lastSelectionText = dv;
14426 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14433 reset : function(){
14434 // overridden so that last data is reset..
14441 this.setValue(this.originalValue);
14442 //this.clearInvalid();
14443 this.lastData = false;
14445 this.view.clearSelections();
14451 findRecord : function(prop, value){
14453 if(this.store.getCount() > 0){
14454 this.store.each(function(r){
14455 if(r.data[prop] == value){
14465 getName: function()
14467 // returns hidden if it's set..
14468 if (!this.rendered) {return ''};
14469 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14473 onViewMove : function(e, t){
14474 this.inKeyMode = false;
14478 onViewOver : function(e, t){
14479 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14482 var item = this.view.findItemFromChild(t);
14485 var index = this.view.indexOf(item);
14486 this.select(index, false);
14491 onViewClick : function(view, doFocus, el, e)
14493 var index = this.view.getSelectedIndexes()[0];
14495 var r = this.store.getAt(index);
14499 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14506 Roo.each(this.tickItems, function(v,k){
14508 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14510 _this.tickItems.splice(k, 1);
14512 if(typeof(e) == 'undefined' && view == false){
14513 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14525 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14526 this.tickItems.push(r.data);
14529 if(typeof(e) == 'undefined' && view == false){
14530 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14537 this.onSelect(r, index);
14539 if(doFocus !== false && !this.blockFocus){
14540 this.inputEl().focus();
14545 restrictHeight : function(){
14546 //this.innerList.dom.style.height = '';
14547 //var inner = this.innerList.dom;
14548 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14549 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14550 //this.list.beginUpdate();
14551 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14552 this.list.alignTo(this.inputEl(), this.listAlign);
14553 this.list.alignTo(this.inputEl(), this.listAlign);
14554 //this.list.endUpdate();
14558 onEmptyResults : function(){
14560 if(this.tickable && this.editable){
14561 this.hasFocus = false;
14562 this.restrictHeight();
14570 * Returns true if the dropdown list is expanded, else false.
14572 isExpanded : function(){
14573 return this.list.isVisible();
14577 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14578 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14579 * @param {String} value The data value of the item to select
14580 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14581 * selected item if it is not currently in view (defaults to true)
14582 * @return {Boolean} True if the value matched an item in the list, else false
14584 selectByValue : function(v, scrollIntoView){
14585 if(v !== undefined && v !== null){
14586 var r = this.findRecord(this.valueField || this.displayField, v);
14588 this.select(this.store.indexOf(r), scrollIntoView);
14596 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14597 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14598 * @param {Number} index The zero-based index of the list item to select
14599 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14600 * selected item if it is not currently in view (defaults to true)
14602 select : function(index, scrollIntoView){
14603 this.selectedIndex = index;
14604 this.view.select(index);
14605 if(scrollIntoView !== false){
14606 var el = this.view.getNode(index);
14608 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14611 this.list.scrollChildIntoView(el, false);
14617 selectNext : function(){
14618 var ct = this.store.getCount();
14620 if(this.selectedIndex == -1){
14622 }else if(this.selectedIndex < ct-1){
14623 this.select(this.selectedIndex+1);
14629 selectPrev : function(){
14630 var ct = this.store.getCount();
14632 if(this.selectedIndex == -1){
14634 }else if(this.selectedIndex != 0){
14635 this.select(this.selectedIndex-1);
14641 onKeyUp : function(e){
14642 if(this.editable !== false && !e.isSpecialKey()){
14643 this.lastKey = e.getKey();
14644 this.dqTask.delay(this.queryDelay);
14649 validateBlur : function(){
14650 return !this.list || !this.list.isVisible();
14654 initQuery : function(){
14656 var v = this.getRawValue();
14658 if(this.tickable && this.editable){
14659 v = this.tickableInputEl().getValue();
14666 doForce : function(){
14667 if(this.inputEl().dom.value.length > 0){
14668 this.inputEl().dom.value =
14669 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14675 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14676 * query allowing the query action to be canceled if needed.
14677 * @param {String} query The SQL query to execute
14678 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14679 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14680 * saved in the current store (defaults to false)
14682 doQuery : function(q, forceAll){
14684 if(q === undefined || q === null){
14689 forceAll: forceAll,
14693 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14698 forceAll = qe.forceAll;
14699 if(forceAll === true || (q.length >= this.minChars)){
14701 this.hasQuery = true;
14703 if(this.lastQuery != q || this.alwaysQuery){
14704 this.lastQuery = q;
14705 if(this.mode == 'local'){
14706 this.selectedIndex = -1;
14708 this.store.clearFilter();
14711 if(this.specialFilter){
14712 this.fireEvent('specialfilter', this);
14717 this.store.filter(this.displayField, q);
14720 this.store.fireEvent("datachanged", this.store);
14727 this.store.baseParams[this.queryParam] = q;
14729 var options = {params : this.getParams(q)};
14732 options.add = true;
14733 options.params.start = this.page * this.pageSize;
14736 this.store.load(options);
14739 * this code will make the page width larger, at the beginning, the list not align correctly,
14740 * we should expand the list on onLoad
14741 * so command out it
14746 this.selectedIndex = -1;
14751 this.loadNext = false;
14755 getParams : function(q){
14757 //p[this.queryParam] = q;
14761 p.limit = this.pageSize;
14767 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14769 collapse : function(){
14770 if(!this.isExpanded()){
14776 this.hasFocus = false;
14780 this.cancelBtn.hide();
14781 this.trigger.show();
14784 this.tickableInputEl().dom.value = '';
14785 this.tickableInputEl().blur();
14790 Roo.get(document).un('mousedown', this.collapseIf, this);
14791 Roo.get(document).un('mousewheel', this.collapseIf, this);
14792 if (!this.editable) {
14793 Roo.get(document).un('keydown', this.listKeyPress, this);
14795 this.fireEvent('collapse', this);
14801 collapseIf : function(e){
14802 var in_combo = e.within(this.el);
14803 var in_list = e.within(this.list);
14804 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14806 if (in_combo || in_list || is_list) {
14807 //e.stopPropagation();
14812 this.onTickableFooterButtonClick(e, false, false);
14820 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14822 expand : function(){
14824 if(this.isExpanded() || !this.hasFocus){
14828 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14829 this.list.setWidth(lw);
14835 this.restrictHeight();
14839 this.tickItems = Roo.apply([], this.item);
14842 this.cancelBtn.show();
14843 this.trigger.hide();
14846 this.tickableInputEl().focus();
14851 Roo.get(document).on('mousedown', this.collapseIf, this);
14852 Roo.get(document).on('mousewheel', this.collapseIf, this);
14853 if (!this.editable) {
14854 Roo.get(document).on('keydown', this.listKeyPress, this);
14857 this.fireEvent('expand', this);
14861 // Implements the default empty TriggerField.onTriggerClick function
14862 onTriggerClick : function(e)
14864 Roo.log('trigger click');
14866 if(this.disabled || !this.triggerList){
14871 this.loadNext = false;
14873 if(this.isExpanded()){
14875 if (!this.blockFocus) {
14876 this.inputEl().focus();
14880 this.hasFocus = true;
14881 if(this.triggerAction == 'all') {
14882 this.doQuery(this.allQuery, true);
14884 this.doQuery(this.getRawValue());
14886 if (!this.blockFocus) {
14887 this.inputEl().focus();
14892 onTickableTriggerClick : function(e)
14899 this.loadNext = false;
14900 this.hasFocus = true;
14902 if(this.triggerAction == 'all') {
14903 this.doQuery(this.allQuery, true);
14905 this.doQuery(this.getRawValue());
14909 onSearchFieldClick : function(e)
14911 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14912 this.onTickableFooterButtonClick(e, false, false);
14916 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14921 this.loadNext = false;
14922 this.hasFocus = true;
14924 if(this.triggerAction == 'all') {
14925 this.doQuery(this.allQuery, true);
14927 this.doQuery(this.getRawValue());
14931 listKeyPress : function(e)
14933 //Roo.log('listkeypress');
14934 // scroll to first matching element based on key pres..
14935 if (e.isSpecialKey()) {
14938 var k = String.fromCharCode(e.getKey()).toUpperCase();
14941 var csel = this.view.getSelectedNodes();
14942 var cselitem = false;
14944 var ix = this.view.indexOf(csel[0]);
14945 cselitem = this.store.getAt(ix);
14946 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14952 this.store.each(function(v) {
14954 // start at existing selection.
14955 if (cselitem.id == v.id) {
14961 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14962 match = this.store.indexOf(v);
14968 if (match === false) {
14969 return true; // no more action?
14972 this.view.select(match);
14973 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14974 sn.scrollIntoView(sn.dom.parentNode, false);
14977 onViewScroll : function(e, t){
14979 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){
14983 this.hasQuery = true;
14985 this.loading = this.list.select('.loading', true).first();
14987 if(this.loading === null){
14988 this.list.createChild({
14990 cls: 'loading roo-select2-more-results roo-select2-active',
14991 html: 'Loading more results...'
14994 this.loading = this.list.select('.loading', true).first();
14996 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14998 this.loading.hide();
15001 this.loading.show();
15006 this.loadNext = true;
15008 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15013 addItem : function(o)
15015 var dv = ''; // display value
15017 if (this.displayField) {
15018 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15020 // this is an error condition!!!
15021 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15028 var choice = this.choices.createChild({
15030 cls: 'roo-select2-search-choice',
15039 cls: 'roo-select2-search-choice-close fa fa-times',
15044 }, this.searchField);
15046 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15048 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15056 this.inputEl().dom.value = '';
15061 onRemoveItem : function(e, _self, o)
15063 e.preventDefault();
15065 this.lastItem = Roo.apply([], this.item);
15067 var index = this.item.indexOf(o.data) * 1;
15070 Roo.log('not this item?!');
15074 this.item.splice(index, 1);
15079 this.fireEvent('remove', this, e);
15085 syncValue : function()
15087 if(!this.item.length){
15094 Roo.each(this.item, function(i){
15095 if(_this.valueField){
15096 value.push(i[_this.valueField]);
15103 this.value = value.join(',');
15105 if(this.hiddenField){
15106 this.hiddenField.dom.value = this.value;
15109 this.store.fireEvent("datachanged", this.store);
15114 clearItem : function()
15116 if(!this.multiple){
15122 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15130 if(this.tickable && !Roo.isTouch){
15131 this.view.refresh();
15135 inputEl: function ()
15137 if(Roo.isIOS && this.useNativeIOS){
15138 return this.el.select('select.roo-ios-select', true).first();
15141 if(Roo.isTouch && this.mobileTouchView){
15142 return this.el.select('input.form-control',true).first();
15146 return this.searchField;
15149 return this.el.select('input.form-control',true).first();
15152 onTickableFooterButtonClick : function(e, btn, el)
15154 e.preventDefault();
15156 this.lastItem = Roo.apply([], this.item);
15158 if(btn && btn.name == 'cancel'){
15159 this.tickItems = Roo.apply([], this.item);
15168 Roo.each(this.tickItems, function(o){
15176 validate : function()
15178 if(this.getVisibilityEl().hasClass('hidden')){
15182 var v = this.getRawValue();
15185 v = this.getValue();
15188 if(this.disabled || this.allowBlank || v.length){
15193 this.markInvalid();
15197 tickableInputEl : function()
15199 if(!this.tickable || !this.editable){
15200 return this.inputEl();
15203 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15207 getAutoCreateTouchView : function()
15212 cls: 'form-group' //input-group
15218 type : this.inputType,
15219 cls : 'form-control x-combo-noedit',
15220 autocomplete: 'new-password',
15221 placeholder : this.placeholder || '',
15226 input.name = this.name;
15230 input.cls += ' input-' + this.size;
15233 if (this.disabled) {
15234 input.disabled = true;
15245 inputblock.cls += ' input-group';
15247 inputblock.cn.unshift({
15249 cls : 'input-group-addon input-group-prepend input-group-text',
15254 if(this.removable && !this.multiple){
15255 inputblock.cls += ' roo-removable';
15257 inputblock.cn.push({
15260 cls : 'roo-combo-removable-btn close'
15264 if(this.hasFeedback && !this.allowBlank){
15266 inputblock.cls += ' has-feedback';
15268 inputblock.cn.push({
15270 cls: 'glyphicon form-control-feedback'
15277 inputblock.cls += (this.before) ? '' : ' input-group';
15279 inputblock.cn.push({
15281 cls : 'input-group-addon input-group-append input-group-text',
15287 var ibwrap = inputblock;
15292 cls: 'roo-select2-choices',
15296 cls: 'roo-select2-search-field',
15309 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15314 cls: 'form-hidden-field'
15320 if(!this.multiple && this.showToggleBtn){
15327 if (this.caret != false) {
15330 cls: 'fa fa-' + this.caret
15337 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15342 cls: 'combobox-clear',
15356 combobox.cls += ' roo-select2-container-multi';
15359 var align = this.labelAlign || this.parentLabelAlign();
15361 if (align ==='left' && this.fieldLabel.length) {
15366 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15367 tooltip : 'This field is required'
15371 cls : 'control-label col-form-label',
15372 html : this.fieldLabel
15383 var labelCfg = cfg.cn[1];
15384 var contentCfg = cfg.cn[2];
15387 if(this.indicatorpos == 'right'){
15392 cls : 'control-label col-form-label',
15396 html : this.fieldLabel
15400 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15401 tooltip : 'This field is required'
15414 labelCfg = cfg.cn[0];
15415 contentCfg = cfg.cn[1];
15420 if(this.labelWidth > 12){
15421 labelCfg.style = "width: " + this.labelWidth + 'px';
15424 if(this.labelWidth < 13 && this.labelmd == 0){
15425 this.labelmd = this.labelWidth;
15428 if(this.labellg > 0){
15429 labelCfg.cls += ' col-lg-' + this.labellg;
15430 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15433 if(this.labelmd > 0){
15434 labelCfg.cls += ' col-md-' + this.labelmd;
15435 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15438 if(this.labelsm > 0){
15439 labelCfg.cls += ' col-sm-' + this.labelsm;
15440 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15443 if(this.labelxs > 0){
15444 labelCfg.cls += ' col-xs-' + this.labelxs;
15445 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15449 } else if ( this.fieldLabel.length) {
15453 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15454 tooltip : 'This field is required'
15458 cls : 'control-label',
15459 html : this.fieldLabel
15470 if(this.indicatorpos == 'right'){
15474 cls : 'control-label',
15475 html : this.fieldLabel,
15479 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15480 tooltip : 'This field is required'
15497 var settings = this;
15499 ['xs','sm','md','lg'].map(function(size){
15500 if (settings[size]) {
15501 cfg.cls += ' col-' + size + '-' + settings[size];
15508 initTouchView : function()
15510 this.renderTouchView();
15512 this.touchViewEl.on('scroll', function(){
15513 this.el.dom.scrollTop = 0;
15516 this.originalValue = this.getValue();
15518 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15520 this.inputEl().on("click", this.showTouchView, this);
15521 if (this.triggerEl) {
15522 this.triggerEl.on("click", this.showTouchView, this);
15526 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15527 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15529 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15531 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15532 this.store.on('load', this.onTouchViewLoad, this);
15533 this.store.on('loadexception', this.onTouchViewLoadException, this);
15535 if(this.hiddenName){
15537 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15539 this.hiddenField.dom.value =
15540 this.hiddenValue !== undefined ? this.hiddenValue :
15541 this.value !== undefined ? this.value : '';
15543 this.el.dom.removeAttribute('name');
15544 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15548 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15549 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15552 if(this.removable && !this.multiple){
15553 var close = this.closeTriggerEl();
15555 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15556 close.on('click', this.removeBtnClick, this, close);
15560 * fix the bug in Safari iOS8
15562 this.inputEl().on("focus", function(e){
15563 document.activeElement.blur();
15566 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15573 renderTouchView : function()
15575 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15576 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15578 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15579 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15581 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15582 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15583 this.touchViewBodyEl.setStyle('overflow', 'auto');
15585 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15586 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15588 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15589 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15593 showTouchView : function()
15599 this.touchViewHeaderEl.hide();
15601 if(this.modalTitle.length){
15602 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15603 this.touchViewHeaderEl.show();
15606 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15607 this.touchViewEl.show();
15609 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15611 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15612 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15614 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15616 if(this.modalTitle.length){
15617 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15620 this.touchViewBodyEl.setHeight(bodyHeight);
15624 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15626 this.touchViewEl.addClass('in');
15629 if(this._touchViewMask){
15630 Roo.get(document.body).addClass("x-body-masked");
15631 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15632 this._touchViewMask.setStyle('z-index', 10000);
15633 this._touchViewMask.addClass('show');
15636 this.doTouchViewQuery();
15640 hideTouchView : function()
15642 this.touchViewEl.removeClass('in');
15646 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15648 this.touchViewEl.setStyle('display', 'none');
15651 if(this._touchViewMask){
15652 this._touchViewMask.removeClass('show');
15653 Roo.get(document.body).removeClass("x-body-masked");
15657 setTouchViewValue : function()
15664 Roo.each(this.tickItems, function(o){
15669 this.hideTouchView();
15672 doTouchViewQuery : function()
15681 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15685 if(!this.alwaysQuery || this.mode == 'local'){
15686 this.onTouchViewLoad();
15693 onTouchViewBeforeLoad : function(combo,opts)
15699 onTouchViewLoad : function()
15701 if(this.store.getCount() < 1){
15702 this.onTouchViewEmptyResults();
15706 this.clearTouchView();
15708 var rawValue = this.getRawValue();
15710 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15712 this.tickItems = [];
15714 this.store.data.each(function(d, rowIndex){
15715 var row = this.touchViewListGroup.createChild(template);
15717 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15718 row.addClass(d.data.cls);
15721 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15724 html : d.data[this.displayField]
15727 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15728 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15731 row.removeClass('selected');
15732 if(!this.multiple && this.valueField &&
15733 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15736 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15737 row.addClass('selected');
15740 if(this.multiple && this.valueField &&
15741 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15745 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15746 this.tickItems.push(d.data);
15749 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15753 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15755 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15757 if(this.modalTitle.length){
15758 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15761 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15763 if(this.mobile_restrict_height && listHeight < bodyHeight){
15764 this.touchViewBodyEl.setHeight(listHeight);
15769 if(firstChecked && listHeight > bodyHeight){
15770 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15775 onTouchViewLoadException : function()
15777 this.hideTouchView();
15780 onTouchViewEmptyResults : function()
15782 this.clearTouchView();
15784 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15786 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15790 clearTouchView : function()
15792 this.touchViewListGroup.dom.innerHTML = '';
15795 onTouchViewClick : function(e, el, o)
15797 e.preventDefault();
15800 var rowIndex = o.rowIndex;
15802 var r = this.store.getAt(rowIndex);
15804 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15806 if(!this.multiple){
15807 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15808 c.dom.removeAttribute('checked');
15811 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15813 this.setFromData(r.data);
15815 var close = this.closeTriggerEl();
15821 this.hideTouchView();
15823 this.fireEvent('select', this, r, rowIndex);
15828 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15829 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15830 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15834 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15835 this.addItem(r.data);
15836 this.tickItems.push(r.data);
15840 getAutoCreateNativeIOS : function()
15843 cls: 'form-group' //input-group,
15848 cls : 'roo-ios-select'
15852 combobox.name = this.name;
15855 if (this.disabled) {
15856 combobox.disabled = true;
15859 var settings = this;
15861 ['xs','sm','md','lg'].map(function(size){
15862 if (settings[size]) {
15863 cfg.cls += ' col-' + size + '-' + settings[size];
15873 initIOSView : function()
15875 this.store.on('load', this.onIOSViewLoad, this);
15880 onIOSViewLoad : function()
15882 if(this.store.getCount() < 1){
15886 this.clearIOSView();
15888 if(this.allowBlank) {
15890 var default_text = '-- SELECT --';
15892 if(this.placeholder.length){
15893 default_text = this.placeholder;
15896 if(this.emptyTitle.length){
15897 default_text += ' - ' + this.emptyTitle + ' -';
15900 var opt = this.inputEl().createChild({
15903 html : default_text
15907 o[this.valueField] = 0;
15908 o[this.displayField] = default_text;
15910 this.ios_options.push({
15917 this.store.data.each(function(d, rowIndex){
15921 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15922 html = d.data[this.displayField];
15927 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15928 value = d.data[this.valueField];
15937 if(this.value == d.data[this.valueField]){
15938 option['selected'] = true;
15941 var opt = this.inputEl().createChild(option);
15943 this.ios_options.push({
15950 this.inputEl().on('change', function(){
15951 this.fireEvent('select', this);
15956 clearIOSView: function()
15958 this.inputEl().dom.innerHTML = '';
15960 this.ios_options = [];
15963 setIOSValue: function(v)
15967 if(!this.ios_options){
15971 Roo.each(this.ios_options, function(opts){
15973 opts.el.dom.removeAttribute('selected');
15975 if(opts.data[this.valueField] != v){
15979 opts.el.dom.setAttribute('selected', true);
15985 * @cfg {Boolean} grow
15989 * @cfg {Number} growMin
15993 * @cfg {Number} growMax
16002 Roo.apply(Roo.bootstrap.ComboBox, {
16006 cls: 'modal-header',
16028 cls: 'list-group-item',
16032 cls: 'roo-combobox-list-group-item-value'
16036 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16050 listItemCheckbox : {
16052 cls: 'list-group-item',
16056 cls: 'roo-combobox-list-group-item-value'
16060 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16076 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16081 cls: 'modal-footer',
16089 cls: 'col-xs-6 text-left',
16092 cls: 'btn btn-danger roo-touch-view-cancel',
16098 cls: 'col-xs-6 text-right',
16101 cls: 'btn btn-success roo-touch-view-ok',
16112 Roo.apply(Roo.bootstrap.ComboBox, {
16114 touchViewTemplate : {
16116 cls: 'modal fade roo-combobox-touch-view',
16120 cls: 'modal-dialog',
16121 style : 'position:fixed', // we have to fix position....
16125 cls: 'modal-content',
16127 Roo.bootstrap.ComboBox.header,
16128 Roo.bootstrap.ComboBox.body,
16129 Roo.bootstrap.ComboBox.footer
16138 * Ext JS Library 1.1.1
16139 * Copyright(c) 2006-2007, Ext JS, LLC.
16141 * Originally Released Under LGPL - original licence link has changed is not relivant.
16144 * <script type="text/javascript">
16149 * @extends Roo.util.Observable
16150 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16151 * This class also supports single and multi selection modes. <br>
16152 * Create a data model bound view:
16154 var store = new Roo.data.Store(...);
16156 var view = new Roo.View({
16158 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16160 singleSelect: true,
16161 selectedClass: "ydataview-selected",
16165 // listen for node click?
16166 view.on("click", function(vw, index, node, e){
16167 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16171 dataModel.load("foobar.xml");
16173 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16175 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16176 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16178 * Note: old style constructor is still suported (container, template, config)
16181 * Create a new View
16182 * @param {Object} config The config object
16185 Roo.View = function(config, depreciated_tpl, depreciated_config){
16187 this.parent = false;
16189 if (typeof(depreciated_tpl) == 'undefined') {
16190 // new way.. - universal constructor.
16191 Roo.apply(this, config);
16192 this.el = Roo.get(this.el);
16195 this.el = Roo.get(config);
16196 this.tpl = depreciated_tpl;
16197 Roo.apply(this, depreciated_config);
16199 this.wrapEl = this.el.wrap().wrap();
16200 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16203 if(typeof(this.tpl) == "string"){
16204 this.tpl = new Roo.Template(this.tpl);
16206 // support xtype ctors..
16207 this.tpl = new Roo.factory(this.tpl, Roo);
16211 this.tpl.compile();
16216 * @event beforeclick
16217 * Fires before a click is processed. Returns false to cancel the default action.
16218 * @param {Roo.View} this
16219 * @param {Number} index The index of the target node
16220 * @param {HTMLElement} node The target node
16221 * @param {Roo.EventObject} e The raw event object
16223 "beforeclick" : true,
16226 * Fires when a template node is clicked.
16227 * @param {Roo.View} this
16228 * @param {Number} index The index of the target node
16229 * @param {HTMLElement} node The target node
16230 * @param {Roo.EventObject} e The raw event object
16235 * Fires when a template node is double clicked.
16236 * @param {Roo.View} this
16237 * @param {Number} index The index of the target node
16238 * @param {HTMLElement} node The target node
16239 * @param {Roo.EventObject} e The raw event object
16243 * @event contextmenu
16244 * Fires when a template node is right clicked.
16245 * @param {Roo.View} this
16246 * @param {Number} index The index of the target node
16247 * @param {HTMLElement} node The target node
16248 * @param {Roo.EventObject} e The raw event object
16250 "contextmenu" : true,
16252 * @event selectionchange
16253 * Fires when the selected nodes change.
16254 * @param {Roo.View} this
16255 * @param {Array} selections Array of the selected nodes
16257 "selectionchange" : true,
16260 * @event beforeselect
16261 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16262 * @param {Roo.View} this
16263 * @param {HTMLElement} node The node to be selected
16264 * @param {Array} selections Array of currently selected nodes
16266 "beforeselect" : true,
16268 * @event preparedata
16269 * Fires on every row to render, to allow you to change the data.
16270 * @param {Roo.View} this
16271 * @param {Object} data to be rendered (change this)
16273 "preparedata" : true
16281 "click": this.onClick,
16282 "dblclick": this.onDblClick,
16283 "contextmenu": this.onContextMenu,
16287 this.selections = [];
16289 this.cmp = new Roo.CompositeElementLite([]);
16291 this.store = Roo.factory(this.store, Roo.data);
16292 this.setStore(this.store, true);
16295 if ( this.footer && this.footer.xtype) {
16297 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16299 this.footer.dataSource = this.store;
16300 this.footer.container = fctr;
16301 this.footer = Roo.factory(this.footer, Roo);
16302 fctr.insertFirst(this.el);
16304 // this is a bit insane - as the paging toolbar seems to detach the el..
16305 // dom.parentNode.parentNode.parentNode
16306 // they get detached?
16310 Roo.View.superclass.constructor.call(this);
16315 Roo.extend(Roo.View, Roo.util.Observable, {
16318 * @cfg {Roo.data.Store} store Data store to load data from.
16323 * @cfg {String|Roo.Element} el The container element.
16328 * @cfg {String|Roo.Template} tpl The template used by this View
16332 * @cfg {String} dataName the named area of the template to use as the data area
16333 * Works with domtemplates roo-name="name"
16337 * @cfg {String} selectedClass The css class to add to selected nodes
16339 selectedClass : "x-view-selected",
16341 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16346 * @cfg {String} text to display on mask (default Loading)
16350 * @cfg {Boolean} multiSelect Allow multiple selection
16352 multiSelect : false,
16354 * @cfg {Boolean} singleSelect Allow single selection
16356 singleSelect: false,
16359 * @cfg {Boolean} toggleSelect - selecting
16361 toggleSelect : false,
16364 * @cfg {Boolean} tickable - selecting
16369 * Returns the element this view is bound to.
16370 * @return {Roo.Element}
16372 getEl : function(){
16373 return this.wrapEl;
16379 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16381 refresh : function(){
16382 //Roo.log('refresh');
16385 // if we are using something like 'domtemplate', then
16386 // the what gets used is:
16387 // t.applySubtemplate(NAME, data, wrapping data..)
16388 // the outer template then get' applied with
16389 // the store 'extra data'
16390 // and the body get's added to the
16391 // roo-name="data" node?
16392 // <span class='roo-tpl-{name}'></span> ?????
16396 this.clearSelections();
16397 this.el.update("");
16399 var records = this.store.getRange();
16400 if(records.length < 1) {
16402 // is this valid?? = should it render a template??
16404 this.el.update(this.emptyText);
16408 if (this.dataName) {
16409 this.el.update(t.apply(this.store.meta)); //????
16410 el = this.el.child('.roo-tpl-' + this.dataName);
16413 for(var i = 0, len = records.length; i < len; i++){
16414 var data = this.prepareData(records[i].data, i, records[i]);
16415 this.fireEvent("preparedata", this, data, i, records[i]);
16417 var d = Roo.apply({}, data);
16420 Roo.apply(d, {'roo-id' : Roo.id()});
16424 Roo.each(this.parent.item, function(item){
16425 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16428 Roo.apply(d, {'roo-data-checked' : 'checked'});
16432 html[html.length] = Roo.util.Format.trim(
16434 t.applySubtemplate(this.dataName, d, this.store.meta) :
16441 el.update(html.join(""));
16442 this.nodes = el.dom.childNodes;
16443 this.updateIndexes(0);
16448 * Function to override to reformat the data that is sent to
16449 * the template for each node.
16450 * DEPRICATED - use the preparedata event handler.
16451 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16452 * a JSON object for an UpdateManager bound view).
16454 prepareData : function(data, index, record)
16456 this.fireEvent("preparedata", this, data, index, record);
16460 onUpdate : function(ds, record){
16461 // Roo.log('on update');
16462 this.clearSelections();
16463 var index = this.store.indexOf(record);
16464 var n = this.nodes[index];
16465 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16466 n.parentNode.removeChild(n);
16467 this.updateIndexes(index, index);
16473 onAdd : function(ds, records, index)
16475 //Roo.log(['on Add', ds, records, index] );
16476 this.clearSelections();
16477 if(this.nodes.length == 0){
16481 var n = this.nodes[index];
16482 for(var i = 0, len = records.length; i < len; i++){
16483 var d = this.prepareData(records[i].data, i, records[i]);
16485 this.tpl.insertBefore(n, d);
16488 this.tpl.append(this.el, d);
16491 this.updateIndexes(index);
16494 onRemove : function(ds, record, index){
16495 // Roo.log('onRemove');
16496 this.clearSelections();
16497 var el = this.dataName ?
16498 this.el.child('.roo-tpl-' + this.dataName) :
16501 el.dom.removeChild(this.nodes[index]);
16502 this.updateIndexes(index);
16506 * Refresh an individual node.
16507 * @param {Number} index
16509 refreshNode : function(index){
16510 this.onUpdate(this.store, this.store.getAt(index));
16513 updateIndexes : function(startIndex, endIndex){
16514 var ns = this.nodes;
16515 startIndex = startIndex || 0;
16516 endIndex = endIndex || ns.length - 1;
16517 for(var i = startIndex; i <= endIndex; i++){
16518 ns[i].nodeIndex = i;
16523 * Changes the data store this view uses and refresh the view.
16524 * @param {Store} store
16526 setStore : function(store, initial){
16527 if(!initial && this.store){
16528 this.store.un("datachanged", this.refresh);
16529 this.store.un("add", this.onAdd);
16530 this.store.un("remove", this.onRemove);
16531 this.store.un("update", this.onUpdate);
16532 this.store.un("clear", this.refresh);
16533 this.store.un("beforeload", this.onBeforeLoad);
16534 this.store.un("load", this.onLoad);
16535 this.store.un("loadexception", this.onLoad);
16539 store.on("datachanged", this.refresh, this);
16540 store.on("add", this.onAdd, this);
16541 store.on("remove", this.onRemove, this);
16542 store.on("update", this.onUpdate, this);
16543 store.on("clear", this.refresh, this);
16544 store.on("beforeload", this.onBeforeLoad, this);
16545 store.on("load", this.onLoad, this);
16546 store.on("loadexception", this.onLoad, this);
16554 * onbeforeLoad - masks the loading area.
16557 onBeforeLoad : function(store,opts)
16559 //Roo.log('onBeforeLoad');
16561 this.el.update("");
16563 this.el.mask(this.mask ? this.mask : "Loading" );
16565 onLoad : function ()
16572 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16573 * @param {HTMLElement} node
16574 * @return {HTMLElement} The template node
16576 findItemFromChild : function(node){
16577 var el = this.dataName ?
16578 this.el.child('.roo-tpl-' + this.dataName,true) :
16581 if(!node || node.parentNode == el){
16584 var p = node.parentNode;
16585 while(p && p != el){
16586 if(p.parentNode == el){
16595 onClick : function(e){
16596 var item = this.findItemFromChild(e.getTarget());
16598 var index = this.indexOf(item);
16599 if(this.onItemClick(item, index, e) !== false){
16600 this.fireEvent("click", this, index, item, e);
16603 this.clearSelections();
16608 onContextMenu : function(e){
16609 var item = this.findItemFromChild(e.getTarget());
16611 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16616 onDblClick : function(e){
16617 var item = this.findItemFromChild(e.getTarget());
16619 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16623 onItemClick : function(item, index, e)
16625 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16628 if (this.toggleSelect) {
16629 var m = this.isSelected(item) ? 'unselect' : 'select';
16632 _t[m](item, true, false);
16635 if(this.multiSelect || this.singleSelect){
16636 if(this.multiSelect && e.shiftKey && this.lastSelection){
16637 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16639 this.select(item, this.multiSelect && e.ctrlKey);
16640 this.lastSelection = item;
16643 if(!this.tickable){
16644 e.preventDefault();
16652 * Get the number of selected nodes.
16655 getSelectionCount : function(){
16656 return this.selections.length;
16660 * Get the currently selected nodes.
16661 * @return {Array} An array of HTMLElements
16663 getSelectedNodes : function(){
16664 return this.selections;
16668 * Get the indexes of the selected nodes.
16671 getSelectedIndexes : function(){
16672 var indexes = [], s = this.selections;
16673 for(var i = 0, len = s.length; i < len; i++){
16674 indexes.push(s[i].nodeIndex);
16680 * Clear all selections
16681 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16683 clearSelections : function(suppressEvent){
16684 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16685 this.cmp.elements = this.selections;
16686 this.cmp.removeClass(this.selectedClass);
16687 this.selections = [];
16688 if(!suppressEvent){
16689 this.fireEvent("selectionchange", this, this.selections);
16695 * Returns true if the passed node is selected
16696 * @param {HTMLElement/Number} node The node or node index
16697 * @return {Boolean}
16699 isSelected : function(node){
16700 var s = this.selections;
16704 node = this.getNode(node);
16705 return s.indexOf(node) !== -1;
16710 * @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
16711 * @param {Boolean} keepExisting (optional) true to keep existing selections
16712 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16714 select : function(nodeInfo, keepExisting, suppressEvent){
16715 if(nodeInfo instanceof Array){
16717 this.clearSelections(true);
16719 for(var i = 0, len = nodeInfo.length; i < len; i++){
16720 this.select(nodeInfo[i], true, true);
16724 var node = this.getNode(nodeInfo);
16725 if(!node || this.isSelected(node)){
16726 return; // already selected.
16729 this.clearSelections(true);
16732 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16733 Roo.fly(node).addClass(this.selectedClass);
16734 this.selections.push(node);
16735 if(!suppressEvent){
16736 this.fireEvent("selectionchange", this, this.selections);
16744 * @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
16745 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16746 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16748 unselect : function(nodeInfo, keepExisting, suppressEvent)
16750 if(nodeInfo instanceof Array){
16751 Roo.each(this.selections, function(s) {
16752 this.unselect(s, nodeInfo);
16756 var node = this.getNode(nodeInfo);
16757 if(!node || !this.isSelected(node)){
16758 //Roo.log("not selected");
16759 return; // not selected.
16763 Roo.each(this.selections, function(s) {
16765 Roo.fly(node).removeClass(this.selectedClass);
16772 this.selections= ns;
16773 this.fireEvent("selectionchange", this, this.selections);
16777 * Gets a template node.
16778 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16779 * @return {HTMLElement} The node or null if it wasn't found
16781 getNode : function(nodeInfo){
16782 if(typeof nodeInfo == "string"){
16783 return document.getElementById(nodeInfo);
16784 }else if(typeof nodeInfo == "number"){
16785 return this.nodes[nodeInfo];
16791 * Gets a range template nodes.
16792 * @param {Number} startIndex
16793 * @param {Number} endIndex
16794 * @return {Array} An array of nodes
16796 getNodes : function(start, end){
16797 var ns = this.nodes;
16798 start = start || 0;
16799 end = typeof end == "undefined" ? ns.length - 1 : end;
16802 for(var i = start; i <= end; i++){
16806 for(var i = start; i >= end; i--){
16814 * Finds the index of the passed node
16815 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16816 * @return {Number} The index of the node or -1
16818 indexOf : function(node){
16819 node = this.getNode(node);
16820 if(typeof node.nodeIndex == "number"){
16821 return node.nodeIndex;
16823 var ns = this.nodes;
16824 for(var i = 0, len = ns.length; i < len; i++){
16835 * based on jquery fullcalendar
16839 Roo.bootstrap = Roo.bootstrap || {};
16841 * @class Roo.bootstrap.Calendar
16842 * @extends Roo.bootstrap.Component
16843 * Bootstrap Calendar class
16844 * @cfg {Boolean} loadMask (true|false) default false
16845 * @cfg {Object} header generate the user specific header of the calendar, default false
16848 * Create a new Container
16849 * @param {Object} config The config object
16854 Roo.bootstrap.Calendar = function(config){
16855 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16859 * Fires when a date is selected
16860 * @param {DatePicker} this
16861 * @param {Date} date The selected date
16865 * @event monthchange
16866 * Fires when the displayed month changes
16867 * @param {DatePicker} this
16868 * @param {Date} date The selected month
16870 'monthchange': true,
16872 * @event evententer
16873 * Fires when mouse over an event
16874 * @param {Calendar} this
16875 * @param {event} Event
16877 'evententer': true,
16879 * @event eventleave
16880 * Fires when the mouse leaves an
16881 * @param {Calendar} this
16884 'eventleave': true,
16886 * @event eventclick
16887 * Fires when the mouse click an
16888 * @param {Calendar} this
16897 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16900 * @cfg {Number} startDay
16901 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16909 getAutoCreate : function(){
16912 var fc_button = function(name, corner, style, content ) {
16913 return Roo.apply({},{
16915 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16917 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16920 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16931 style : 'width:100%',
16938 cls : 'fc-header-left',
16940 fc_button('prev', 'left', 'arrow', '‹' ),
16941 fc_button('next', 'right', 'arrow', '›' ),
16942 { tag: 'span', cls: 'fc-header-space' },
16943 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16951 cls : 'fc-header-center',
16955 cls: 'fc-header-title',
16958 html : 'month / year'
16966 cls : 'fc-header-right',
16968 /* fc_button('month', 'left', '', 'month' ),
16969 fc_button('week', '', '', 'week' ),
16970 fc_button('day', 'right', '', 'day' )
16982 header = this.header;
16985 var cal_heads = function() {
16987 // fixme - handle this.
16989 for (var i =0; i < Date.dayNames.length; i++) {
16990 var d = Date.dayNames[i];
16993 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16994 html : d.substring(0,3)
16998 ret[0].cls += ' fc-first';
16999 ret[6].cls += ' fc-last';
17002 var cal_cell = function(n) {
17005 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17010 cls: 'fc-day-number',
17014 cls: 'fc-day-content',
17018 style: 'position: relative;' // height: 17px;
17030 var cal_rows = function() {
17033 for (var r = 0; r < 6; r++) {
17040 for (var i =0; i < Date.dayNames.length; i++) {
17041 var d = Date.dayNames[i];
17042 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17045 row.cn[0].cls+=' fc-first';
17046 row.cn[0].cn[0].style = 'min-height:90px';
17047 row.cn[6].cls+=' fc-last';
17051 ret[0].cls += ' fc-first';
17052 ret[4].cls += ' fc-prev-last';
17053 ret[5].cls += ' fc-last';
17060 cls: 'fc-border-separate',
17061 style : 'width:100%',
17069 cls : 'fc-first fc-last',
17087 cls : 'fc-content',
17088 style : "position: relative;",
17091 cls : 'fc-view fc-view-month fc-grid',
17092 style : 'position: relative',
17093 unselectable : 'on',
17096 cls : 'fc-event-container',
17097 style : 'position:absolute;z-index:8;top:0;left:0;'
17115 initEvents : function()
17118 throw "can not find store for calendar";
17124 style: "text-align:center",
17128 style: "background-color:white;width:50%;margin:250 auto",
17132 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17143 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17145 var size = this.el.select('.fc-content', true).first().getSize();
17146 this.maskEl.setSize(size.width, size.height);
17147 this.maskEl.enableDisplayMode("block");
17148 if(!this.loadMask){
17149 this.maskEl.hide();
17152 this.store = Roo.factory(this.store, Roo.data);
17153 this.store.on('load', this.onLoad, this);
17154 this.store.on('beforeload', this.onBeforeLoad, this);
17158 this.cells = this.el.select('.fc-day',true);
17159 //Roo.log(this.cells);
17160 this.textNodes = this.el.query('.fc-day-number');
17161 this.cells.addClassOnOver('fc-state-hover');
17163 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17164 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17165 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17166 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17168 this.on('monthchange', this.onMonthChange, this);
17170 this.update(new Date().clearTime());
17173 resize : function() {
17174 var sz = this.el.getSize();
17176 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17177 this.el.select('.fc-day-content div',true).setHeight(34);
17182 showPrevMonth : function(e){
17183 this.update(this.activeDate.add("mo", -1));
17185 showToday : function(e){
17186 this.update(new Date().clearTime());
17189 showNextMonth : function(e){
17190 this.update(this.activeDate.add("mo", 1));
17194 showPrevYear : function(){
17195 this.update(this.activeDate.add("y", -1));
17199 showNextYear : function(){
17200 this.update(this.activeDate.add("y", 1));
17205 update : function(date)
17207 var vd = this.activeDate;
17208 this.activeDate = date;
17209 // if(vd && this.el){
17210 // var t = date.getTime();
17211 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17212 // Roo.log('using add remove');
17214 // this.fireEvent('monthchange', this, date);
17216 // this.cells.removeClass("fc-state-highlight");
17217 // this.cells.each(function(c){
17218 // if(c.dateValue == t){
17219 // c.addClass("fc-state-highlight");
17220 // setTimeout(function(){
17221 // try{c.dom.firstChild.focus();}catch(e){}
17231 var days = date.getDaysInMonth();
17233 var firstOfMonth = date.getFirstDateOfMonth();
17234 var startingPos = firstOfMonth.getDay()-this.startDay;
17236 if(startingPos < this.startDay){
17240 var pm = date.add(Date.MONTH, -1);
17241 var prevStart = pm.getDaysInMonth()-startingPos;
17243 this.cells = this.el.select('.fc-day',true);
17244 this.textNodes = this.el.query('.fc-day-number');
17245 this.cells.addClassOnOver('fc-state-hover');
17247 var cells = this.cells.elements;
17248 var textEls = this.textNodes;
17250 Roo.each(cells, function(cell){
17251 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17254 days += startingPos;
17256 // convert everything to numbers so it's fast
17257 var day = 86400000;
17258 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17261 //Roo.log(prevStart);
17263 var today = new Date().clearTime().getTime();
17264 var sel = date.clearTime().getTime();
17265 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17266 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17267 var ddMatch = this.disabledDatesRE;
17268 var ddText = this.disabledDatesText;
17269 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17270 var ddaysText = this.disabledDaysText;
17271 var format = this.format;
17273 var setCellClass = function(cal, cell){
17277 //Roo.log('set Cell Class');
17279 var t = d.getTime();
17283 cell.dateValue = t;
17285 cell.className += " fc-today";
17286 cell.className += " fc-state-highlight";
17287 cell.title = cal.todayText;
17290 // disable highlight in other month..
17291 //cell.className += " fc-state-highlight";
17296 cell.className = " fc-state-disabled";
17297 cell.title = cal.minText;
17301 cell.className = " fc-state-disabled";
17302 cell.title = cal.maxText;
17306 if(ddays.indexOf(d.getDay()) != -1){
17307 cell.title = ddaysText;
17308 cell.className = " fc-state-disabled";
17311 if(ddMatch && format){
17312 var fvalue = d.dateFormat(format);
17313 if(ddMatch.test(fvalue)){
17314 cell.title = ddText.replace("%0", fvalue);
17315 cell.className = " fc-state-disabled";
17319 if (!cell.initialClassName) {
17320 cell.initialClassName = cell.dom.className;
17323 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17328 for(; i < startingPos; i++) {
17329 textEls[i].innerHTML = (++prevStart);
17330 d.setDate(d.getDate()+1);
17332 cells[i].className = "fc-past fc-other-month";
17333 setCellClass(this, cells[i]);
17338 for(; i < days; i++){
17339 intDay = i - startingPos + 1;
17340 textEls[i].innerHTML = (intDay);
17341 d.setDate(d.getDate()+1);
17343 cells[i].className = ''; // "x-date-active";
17344 setCellClass(this, cells[i]);
17348 for(; i < 42; i++) {
17349 textEls[i].innerHTML = (++extraDays);
17350 d.setDate(d.getDate()+1);
17352 cells[i].className = "fc-future fc-other-month";
17353 setCellClass(this, cells[i]);
17356 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17358 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17360 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17361 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17363 if(totalRows != 6){
17364 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17365 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17368 this.fireEvent('monthchange', this, date);
17372 if(!this.internalRender){
17373 var main = this.el.dom.firstChild;
17374 var w = main.offsetWidth;
17375 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17376 Roo.fly(main).setWidth(w);
17377 this.internalRender = true;
17378 // opera does not respect the auto grow header center column
17379 // then, after it gets a width opera refuses to recalculate
17380 // without a second pass
17381 if(Roo.isOpera && !this.secondPass){
17382 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17383 this.secondPass = true;
17384 this.update.defer(10, this, [date]);
17391 findCell : function(dt) {
17392 dt = dt.clearTime().getTime();
17394 this.cells.each(function(c){
17395 //Roo.log("check " +c.dateValue + '?=' + dt);
17396 if(c.dateValue == dt){
17406 findCells : function(ev) {
17407 var s = ev.start.clone().clearTime().getTime();
17409 var e= ev.end.clone().clearTime().getTime();
17412 this.cells.each(function(c){
17413 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17415 if(c.dateValue > e){
17418 if(c.dateValue < s){
17427 // findBestRow: function(cells)
17431 // for (var i =0 ; i < cells.length;i++) {
17432 // ret = Math.max(cells[i].rows || 0,ret);
17439 addItem : function(ev)
17441 // look for vertical location slot in
17442 var cells = this.findCells(ev);
17444 // ev.row = this.findBestRow(cells);
17446 // work out the location.
17450 for(var i =0; i < cells.length; i++) {
17452 cells[i].row = cells[0].row;
17455 cells[i].row = cells[i].row + 1;
17465 if (crow.start.getY() == cells[i].getY()) {
17467 crow.end = cells[i];
17484 cells[0].events.push(ev);
17486 this.calevents.push(ev);
17489 clearEvents: function() {
17491 if(!this.calevents){
17495 Roo.each(this.cells.elements, function(c){
17501 Roo.each(this.calevents, function(e) {
17502 Roo.each(e.els, function(el) {
17503 el.un('mouseenter' ,this.onEventEnter, this);
17504 el.un('mouseleave' ,this.onEventLeave, this);
17509 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17515 renderEvents: function()
17519 this.cells.each(function(c) {
17528 if(c.row != c.events.length){
17529 r = 4 - (4 - (c.row - c.events.length));
17532 c.events = ev.slice(0, r);
17533 c.more = ev.slice(r);
17535 if(c.more.length && c.more.length == 1){
17536 c.events.push(c.more.pop());
17539 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17543 this.cells.each(function(c) {
17545 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17548 for (var e = 0; e < c.events.length; e++){
17549 var ev = c.events[e];
17550 var rows = ev.rows;
17552 for(var i = 0; i < rows.length; i++) {
17554 // how many rows should it span..
17557 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17558 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17560 unselectable : "on",
17563 cls: 'fc-event-inner',
17567 // cls: 'fc-event-time',
17568 // html : cells.length > 1 ? '' : ev.time
17572 cls: 'fc-event-title',
17573 html : String.format('{0}', ev.title)
17580 cls: 'ui-resizable-handle ui-resizable-e',
17581 html : '  '
17588 cfg.cls += ' fc-event-start';
17590 if ((i+1) == rows.length) {
17591 cfg.cls += ' fc-event-end';
17594 var ctr = _this.el.select('.fc-event-container',true).first();
17595 var cg = ctr.createChild(cfg);
17597 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17598 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17600 var r = (c.more.length) ? 1 : 0;
17601 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17602 cg.setWidth(ebox.right - sbox.x -2);
17604 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17605 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17606 cg.on('click', _this.onEventClick, _this, ev);
17617 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17618 style : 'position: absolute',
17619 unselectable : "on",
17622 cls: 'fc-event-inner',
17626 cls: 'fc-event-title',
17634 cls: 'ui-resizable-handle ui-resizable-e',
17635 html : '  '
17641 var ctr = _this.el.select('.fc-event-container',true).first();
17642 var cg = ctr.createChild(cfg);
17644 var sbox = c.select('.fc-day-content',true).first().getBox();
17645 var ebox = c.select('.fc-day-content',true).first().getBox();
17647 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17648 cg.setWidth(ebox.right - sbox.x -2);
17650 cg.on('click', _this.onMoreEventClick, _this, c.more);
17660 onEventEnter: function (e, el,event,d) {
17661 this.fireEvent('evententer', this, el, event);
17664 onEventLeave: function (e, el,event,d) {
17665 this.fireEvent('eventleave', this, el, event);
17668 onEventClick: function (e, el,event,d) {
17669 this.fireEvent('eventclick', this, el, event);
17672 onMonthChange: function () {
17676 onMoreEventClick: function(e, el, more)
17680 this.calpopover.placement = 'right';
17681 this.calpopover.setTitle('More');
17683 this.calpopover.setContent('');
17685 var ctr = this.calpopover.el.select('.popover-content', true).first();
17687 Roo.each(more, function(m){
17689 cls : 'fc-event-hori fc-event-draggable',
17692 var cg = ctr.createChild(cfg);
17694 cg.on('click', _this.onEventClick, _this, m);
17697 this.calpopover.show(el);
17702 onLoad: function ()
17704 this.calevents = [];
17707 if(this.store.getCount() > 0){
17708 this.store.data.each(function(d){
17711 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17712 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17713 time : d.data.start_time,
17714 title : d.data.title,
17715 description : d.data.description,
17716 venue : d.data.venue
17721 this.renderEvents();
17723 if(this.calevents.length && this.loadMask){
17724 this.maskEl.hide();
17728 onBeforeLoad: function()
17730 this.clearEvents();
17732 this.maskEl.show();
17746 * @class Roo.bootstrap.Popover
17747 * @extends Roo.bootstrap.Component
17748 * Bootstrap Popover class
17749 * @cfg {String} html contents of the popover (or false to use children..)
17750 * @cfg {String} title of popover (or false to hide)
17751 * @cfg {String} placement how it is placed
17752 * @cfg {String} trigger click || hover (or false to trigger manually)
17753 * @cfg {String} over what (parent or false to trigger manually.)
17754 * @cfg {Number} delay - delay before showing
17757 * Create a new Popover
17758 * @param {Object} config The config object
17761 Roo.bootstrap.Popover = function(config){
17762 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17768 * After the popover show
17770 * @param {Roo.bootstrap.Popover} this
17775 * After the popover hide
17777 * @param {Roo.bootstrap.Popover} this
17783 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17785 title: 'Fill in a title',
17788 placement : 'right',
17789 trigger : 'hover', // hover
17795 can_build_overlaid : false,
17797 getChildContainer : function()
17799 return this.el.select('.popover-content',true).first();
17802 getAutoCreate : function(){
17805 cls : 'popover roo-dynamic',
17806 style: 'display:block',
17812 cls : 'popover-inner',
17816 cls: 'popover-title popover-header',
17820 cls : 'popover-content popover-body',
17831 setTitle: function(str)
17834 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17836 setContent: function(str)
17839 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17841 // as it get's added to the bottom of the page.
17842 onRender : function(ct, position)
17844 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17846 var cfg = Roo.apply({}, this.getAutoCreate());
17850 cfg.cls += ' ' + this.cls;
17853 cfg.style = this.style;
17855 //Roo.log("adding to ");
17856 this.el = Roo.get(document.body).createChild(cfg, position);
17857 // Roo.log(this.el);
17862 initEvents : function()
17864 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17865 this.el.enableDisplayMode('block');
17867 if (this.over === false) {
17870 if (this.triggers === false) {
17873 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17874 var triggers = this.trigger ? this.trigger.split(' ') : [];
17875 Roo.each(triggers, function(trigger) {
17877 if (trigger == 'click') {
17878 on_el.on('click', this.toggle, this);
17879 } else if (trigger != 'manual') {
17880 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17881 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17883 on_el.on(eventIn ,this.enter, this);
17884 on_el.on(eventOut, this.leave, this);
17895 toggle : function () {
17896 this.hoverState == 'in' ? this.leave() : this.enter();
17899 enter : function () {
17901 clearTimeout(this.timeout);
17903 this.hoverState = 'in';
17905 if (!this.delay || !this.delay.show) {
17910 this.timeout = setTimeout(function () {
17911 if (_t.hoverState == 'in') {
17914 }, this.delay.show)
17917 leave : function() {
17918 clearTimeout(this.timeout);
17920 this.hoverState = 'out';
17922 if (!this.delay || !this.delay.hide) {
17927 this.timeout = setTimeout(function () {
17928 if (_t.hoverState == 'out') {
17931 }, this.delay.hide)
17934 show : function (on_el)
17937 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17941 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17942 if (this.html !== false) {
17943 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17945 this.el.removeClass([
17946 'fade','top','bottom', 'left', 'right','in',
17947 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17949 if (!this.title.length) {
17950 this.el.select('.popover-title',true).hide();
17953 var placement = typeof this.placement == 'function' ?
17954 this.placement.call(this, this.el, on_el) :
17957 var autoToken = /\s?auto?\s?/i;
17958 var autoPlace = autoToken.test(placement);
17960 placement = placement.replace(autoToken, '') || 'top';
17964 //this.el.setXY([0,0]);
17966 this.el.dom.style.display='block';
17967 this.el.addClass(placement);
17969 //this.el.appendTo(on_el);
17971 var p = this.getPosition();
17972 var box = this.el.getBox();
17977 var align = Roo.bootstrap.Popover.alignment[placement];
17980 this.el.alignTo(on_el, align[0],align[1]);
17981 //var arrow = this.el.select('.arrow',true).first();
17982 //arrow.set(align[2],
17984 this.el.addClass('in');
17987 if (this.el.hasClass('fade')) {
17991 this.hoverState = 'in';
17993 this.fireEvent('show', this);
17998 this.el.setXY([0,0]);
17999 this.el.removeClass('in');
18001 this.hoverState = null;
18003 this.fireEvent('hide', this);
18008 Roo.bootstrap.Popover.alignment = {
18009 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18010 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18011 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18012 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18023 * @class Roo.bootstrap.Progress
18024 * @extends Roo.bootstrap.Component
18025 * Bootstrap Progress class
18026 * @cfg {Boolean} striped striped of the progress bar
18027 * @cfg {Boolean} active animated of the progress bar
18031 * Create a new Progress
18032 * @param {Object} config The config object
18035 Roo.bootstrap.Progress = function(config){
18036 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18039 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18044 getAutoCreate : function(){
18052 cfg.cls += ' progress-striped';
18056 cfg.cls += ' active';
18075 * @class Roo.bootstrap.ProgressBar
18076 * @extends Roo.bootstrap.Component
18077 * Bootstrap ProgressBar class
18078 * @cfg {Number} aria_valuenow aria-value now
18079 * @cfg {Number} aria_valuemin aria-value min
18080 * @cfg {Number} aria_valuemax aria-value max
18081 * @cfg {String} label label for the progress bar
18082 * @cfg {String} panel (success | info | warning | danger )
18083 * @cfg {String} role role of the progress bar
18084 * @cfg {String} sr_only text
18088 * Create a new ProgressBar
18089 * @param {Object} config The config object
18092 Roo.bootstrap.ProgressBar = function(config){
18093 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18096 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18100 aria_valuemax : 100,
18106 getAutoCreate : function()
18111 cls: 'progress-bar',
18112 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18124 cfg.role = this.role;
18127 if(this.aria_valuenow){
18128 cfg['aria-valuenow'] = this.aria_valuenow;
18131 if(this.aria_valuemin){
18132 cfg['aria-valuemin'] = this.aria_valuemin;
18135 if(this.aria_valuemax){
18136 cfg['aria-valuemax'] = this.aria_valuemax;
18139 if(this.label && !this.sr_only){
18140 cfg.html = this.label;
18144 cfg.cls += ' progress-bar-' + this.panel;
18150 update : function(aria_valuenow)
18152 this.aria_valuenow = aria_valuenow;
18154 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18169 * @class Roo.bootstrap.TabGroup
18170 * @extends Roo.bootstrap.Column
18171 * Bootstrap Column class
18172 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18173 * @cfg {Boolean} carousel true to make the group behave like a carousel
18174 * @cfg {Boolean} bullets show bullets for the panels
18175 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18176 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18177 * @cfg {Boolean} showarrow (true|false) show arrow default true
18180 * Create a new TabGroup
18181 * @param {Object} config The config object
18184 Roo.bootstrap.TabGroup = function(config){
18185 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18187 this.navId = Roo.id();
18190 Roo.bootstrap.TabGroup.register(this);
18194 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18197 transition : false,
18202 slideOnTouch : false,
18205 getAutoCreate : function()
18207 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18209 cfg.cls += ' tab-content';
18211 if (this.carousel) {
18212 cfg.cls += ' carousel slide';
18215 cls : 'carousel-inner',
18219 if(this.bullets && !Roo.isTouch){
18222 cls : 'carousel-bullets',
18226 if(this.bullets_cls){
18227 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18234 cfg.cn[0].cn.push(bullets);
18237 if(this.showarrow){
18238 cfg.cn[0].cn.push({
18240 class : 'carousel-arrow',
18244 class : 'carousel-prev',
18248 class : 'fa fa-chevron-left'
18254 class : 'carousel-next',
18258 class : 'fa fa-chevron-right'
18271 initEvents: function()
18273 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18274 // this.el.on("touchstart", this.onTouchStart, this);
18277 if(this.autoslide){
18280 this.slideFn = window.setInterval(function() {
18281 _this.showPanelNext();
18285 if(this.showarrow){
18286 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18287 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18293 // onTouchStart : function(e, el, o)
18295 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18299 // this.showPanelNext();
18303 getChildContainer : function()
18305 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18309 * register a Navigation item
18310 * @param {Roo.bootstrap.NavItem} the navitem to add
18312 register : function(item)
18314 this.tabs.push( item);
18315 item.navId = this.navId; // not really needed..
18320 getActivePanel : function()
18323 Roo.each(this.tabs, function(t) {
18333 getPanelByName : function(n)
18336 Roo.each(this.tabs, function(t) {
18337 if (t.tabId == n) {
18345 indexOfPanel : function(p)
18348 Roo.each(this.tabs, function(t,i) {
18349 if (t.tabId == p.tabId) {
18358 * show a specific panel
18359 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18360 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18362 showPanel : function (pan)
18364 if(this.transition || typeof(pan) == 'undefined'){
18365 Roo.log("waiting for the transitionend");
18369 if (typeof(pan) == 'number') {
18370 pan = this.tabs[pan];
18373 if (typeof(pan) == 'string') {
18374 pan = this.getPanelByName(pan);
18377 var cur = this.getActivePanel();
18380 Roo.log('pan or acitve pan is undefined');
18384 if (pan.tabId == this.getActivePanel().tabId) {
18388 if (false === cur.fireEvent('beforedeactivate')) {
18392 if(this.bullets > 0 && !Roo.isTouch){
18393 this.setActiveBullet(this.indexOfPanel(pan));
18396 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18398 //class="carousel-item carousel-item-next carousel-item-left"
18400 this.transition = true;
18401 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18402 var lr = dir == 'next' ? 'left' : 'right';
18403 pan.el.addClass(dir); // or prev
18404 pan.el.addClass('carousel-item-' + dir); // or prev
18405 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18406 cur.el.addClass(lr); // or right
18407 pan.el.addClass(lr);
18408 cur.el.addClass('carousel-item-' +lr); // or right
18409 pan.el.addClass('carousel-item-' +lr);
18413 cur.el.on('transitionend', function() {
18414 Roo.log("trans end?");
18416 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18417 pan.setActive(true);
18419 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18420 cur.setActive(false);
18422 _this.transition = false;
18424 }, this, { single: true } );
18429 cur.setActive(false);
18430 pan.setActive(true);
18435 showPanelNext : function()
18437 var i = this.indexOfPanel(this.getActivePanel());
18439 if (i >= this.tabs.length - 1 && !this.autoslide) {
18443 if (i >= this.tabs.length - 1 && this.autoslide) {
18447 this.showPanel(this.tabs[i+1]);
18450 showPanelPrev : function()
18452 var i = this.indexOfPanel(this.getActivePanel());
18454 if (i < 1 && !this.autoslide) {
18458 if (i < 1 && this.autoslide) {
18459 i = this.tabs.length;
18462 this.showPanel(this.tabs[i-1]);
18466 addBullet: function()
18468 if(!this.bullets || Roo.isTouch){
18471 var ctr = this.el.select('.carousel-bullets',true).first();
18472 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18473 var bullet = ctr.createChild({
18474 cls : 'bullet bullet-' + i
18475 },ctr.dom.lastChild);
18480 bullet.on('click', (function(e, el, o, ii, t){
18482 e.preventDefault();
18484 this.showPanel(ii);
18486 if(this.autoslide && this.slideFn){
18487 clearInterval(this.slideFn);
18488 this.slideFn = window.setInterval(function() {
18489 _this.showPanelNext();
18493 }).createDelegate(this, [i, bullet], true));
18498 setActiveBullet : function(i)
18504 Roo.each(this.el.select('.bullet', true).elements, function(el){
18505 el.removeClass('selected');
18508 var bullet = this.el.select('.bullet-' + i, true).first();
18514 bullet.addClass('selected');
18525 Roo.apply(Roo.bootstrap.TabGroup, {
18529 * register a Navigation Group
18530 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18532 register : function(navgrp)
18534 this.groups[navgrp.navId] = navgrp;
18538 * fetch a Navigation Group based on the navigation ID
18539 * if one does not exist , it will get created.
18540 * @param {string} the navgroup to add
18541 * @returns {Roo.bootstrap.NavGroup} the navgroup
18543 get: function(navId) {
18544 if (typeof(this.groups[navId]) == 'undefined') {
18545 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18547 return this.groups[navId] ;
18562 * @class Roo.bootstrap.TabPanel
18563 * @extends Roo.bootstrap.Component
18564 * Bootstrap TabPanel class
18565 * @cfg {Boolean} active panel active
18566 * @cfg {String} html panel content
18567 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18568 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18569 * @cfg {String} href click to link..
18573 * Create a new TabPanel
18574 * @param {Object} config The config object
18577 Roo.bootstrap.TabPanel = function(config){
18578 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18582 * Fires when the active status changes
18583 * @param {Roo.bootstrap.TabPanel} this
18584 * @param {Boolean} state the new state
18589 * @event beforedeactivate
18590 * Fires before a tab is de-activated - can be used to do validation on a form.
18591 * @param {Roo.bootstrap.TabPanel} this
18592 * @return {Boolean} false if there is an error
18595 'beforedeactivate': true
18598 this.tabId = this.tabId || Roo.id();
18602 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18610 getAutoCreate : function(){
18615 // item is needed for carousel - not sure if it has any effect otherwise
18616 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18617 html: this.html || ''
18621 cfg.cls += ' active';
18625 cfg.tabId = this.tabId;
18633 initEvents: function()
18635 var p = this.parent();
18637 this.navId = this.navId || p.navId;
18639 if (typeof(this.navId) != 'undefined') {
18640 // not really needed.. but just in case.. parent should be a NavGroup.
18641 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18645 var i = tg.tabs.length - 1;
18647 if(this.active && tg.bullets > 0 && i < tg.bullets){
18648 tg.setActiveBullet(i);
18652 this.el.on('click', this.onClick, this);
18655 this.el.on("touchstart", this.onTouchStart, this);
18656 this.el.on("touchmove", this.onTouchMove, this);
18657 this.el.on("touchend", this.onTouchEnd, this);
18662 onRender : function(ct, position)
18664 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18667 setActive : function(state)
18669 Roo.log("panel - set active " + this.tabId + "=" + state);
18671 this.active = state;
18673 this.el.removeClass('active');
18675 } else if (!this.el.hasClass('active')) {
18676 this.el.addClass('active');
18679 this.fireEvent('changed', this, state);
18682 onClick : function(e)
18684 e.preventDefault();
18686 if(!this.href.length){
18690 window.location.href = this.href;
18699 onTouchStart : function(e)
18701 this.swiping = false;
18703 this.startX = e.browserEvent.touches[0].clientX;
18704 this.startY = e.browserEvent.touches[0].clientY;
18707 onTouchMove : function(e)
18709 this.swiping = true;
18711 this.endX = e.browserEvent.touches[0].clientX;
18712 this.endY = e.browserEvent.touches[0].clientY;
18715 onTouchEnd : function(e)
18722 var tabGroup = this.parent();
18724 if(this.endX > this.startX){ // swiping right
18725 tabGroup.showPanelPrev();
18729 if(this.startX > this.endX){ // swiping left
18730 tabGroup.showPanelNext();
18749 * @class Roo.bootstrap.DateField
18750 * @extends Roo.bootstrap.Input
18751 * Bootstrap DateField class
18752 * @cfg {Number} weekStart default 0
18753 * @cfg {String} viewMode default empty, (months|years)
18754 * @cfg {String} minViewMode default empty, (months|years)
18755 * @cfg {Number} startDate default -Infinity
18756 * @cfg {Number} endDate default Infinity
18757 * @cfg {Boolean} todayHighlight default false
18758 * @cfg {Boolean} todayBtn default false
18759 * @cfg {Boolean} calendarWeeks default false
18760 * @cfg {Object} daysOfWeekDisabled default empty
18761 * @cfg {Boolean} singleMode default false (true | false)
18763 * @cfg {Boolean} keyboardNavigation default true
18764 * @cfg {String} language default en
18767 * Create a new DateField
18768 * @param {Object} config The config object
18771 Roo.bootstrap.DateField = function(config){
18772 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18776 * Fires when this field show.
18777 * @param {Roo.bootstrap.DateField} this
18778 * @param {Mixed} date The date value
18783 * Fires when this field hide.
18784 * @param {Roo.bootstrap.DateField} this
18785 * @param {Mixed} date The date value
18790 * Fires when select a date.
18791 * @param {Roo.bootstrap.DateField} this
18792 * @param {Mixed} date The date value
18796 * @event beforeselect
18797 * Fires when before select a date.
18798 * @param {Roo.bootstrap.DateField} this
18799 * @param {Mixed} date The date value
18801 beforeselect : true
18805 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18808 * @cfg {String} format
18809 * The default date format string which can be overriden for localization support. The format must be
18810 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18814 * @cfg {String} altFormats
18815 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18816 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18818 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18826 todayHighlight : false,
18832 keyboardNavigation: true,
18834 calendarWeeks: false,
18836 startDate: -Infinity,
18840 daysOfWeekDisabled: [],
18844 singleMode : false,
18846 UTCDate: function()
18848 return new Date(Date.UTC.apply(Date, arguments));
18851 UTCToday: function()
18853 var today = new Date();
18854 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18857 getDate: function() {
18858 var d = this.getUTCDate();
18859 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18862 getUTCDate: function() {
18866 setDate: function(d) {
18867 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18870 setUTCDate: function(d) {
18872 this.setValue(this.formatDate(this.date));
18875 onRender: function(ct, position)
18878 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18880 this.language = this.language || 'en';
18881 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18882 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18884 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18885 this.format = this.format || 'm/d/y';
18886 this.isInline = false;
18887 this.isInput = true;
18888 this.component = this.el.select('.add-on', true).first() || false;
18889 this.component = (this.component && this.component.length === 0) ? false : this.component;
18890 this.hasInput = this.component && this.inputEl().length;
18892 if (typeof(this.minViewMode === 'string')) {
18893 switch (this.minViewMode) {
18895 this.minViewMode = 1;
18898 this.minViewMode = 2;
18901 this.minViewMode = 0;
18906 if (typeof(this.viewMode === 'string')) {
18907 switch (this.viewMode) {
18920 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18922 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18924 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18926 this.picker().on('mousedown', this.onMousedown, this);
18927 this.picker().on('click', this.onClick, this);
18929 this.picker().addClass('datepicker-dropdown');
18931 this.startViewMode = this.viewMode;
18933 if(this.singleMode){
18934 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18935 v.setVisibilityMode(Roo.Element.DISPLAY);
18939 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18940 v.setStyle('width', '189px');
18944 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18945 if(!this.calendarWeeks){
18950 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18951 v.attr('colspan', function(i, val){
18952 return parseInt(val) + 1;
18957 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18959 this.setStartDate(this.startDate);
18960 this.setEndDate(this.endDate);
18962 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18969 if(this.isInline) {
18974 picker : function()
18976 return this.pickerEl;
18977 // return this.el.select('.datepicker', true).first();
18980 fillDow: function()
18982 var dowCnt = this.weekStart;
18991 if(this.calendarWeeks){
18999 while (dowCnt < this.weekStart + 7) {
19003 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19007 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19010 fillMonths: function()
19013 var months = this.picker().select('>.datepicker-months td', true).first();
19015 months.dom.innerHTML = '';
19021 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19024 months.createChild(month);
19031 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;
19033 if (this.date < this.startDate) {
19034 this.viewDate = new Date(this.startDate);
19035 } else if (this.date > this.endDate) {
19036 this.viewDate = new Date(this.endDate);
19038 this.viewDate = new Date(this.date);
19046 var d = new Date(this.viewDate),
19047 year = d.getUTCFullYear(),
19048 month = d.getUTCMonth(),
19049 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19050 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19051 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19052 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19053 currentDate = this.date && this.date.valueOf(),
19054 today = this.UTCToday();
19056 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19058 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19060 // this.picker.select('>tfoot th.today').
19061 // .text(dates[this.language].today)
19062 // .toggle(this.todayBtn !== false);
19064 this.updateNavArrows();
19067 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19069 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19071 prevMonth.setUTCDate(day);
19073 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19075 var nextMonth = new Date(prevMonth);
19077 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19079 nextMonth = nextMonth.valueOf();
19081 var fillMonths = false;
19083 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19085 while(prevMonth.valueOf() <= nextMonth) {
19088 if (prevMonth.getUTCDay() === this.weekStart) {
19090 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19098 if(this.calendarWeeks){
19099 // ISO 8601: First week contains first thursday.
19100 // ISO also states week starts on Monday, but we can be more abstract here.
19102 // Start of current week: based on weekstart/current date
19103 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19104 // Thursday of this week
19105 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19106 // First Thursday of year, year from thursday
19107 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19108 // Calendar week: ms between thursdays, div ms per day, div 7 days
19109 calWeek = (th - yth) / 864e5 / 7 + 1;
19111 fillMonths.cn.push({
19119 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19121 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19124 if (this.todayHighlight &&
19125 prevMonth.getUTCFullYear() == today.getFullYear() &&
19126 prevMonth.getUTCMonth() == today.getMonth() &&
19127 prevMonth.getUTCDate() == today.getDate()) {
19128 clsName += ' today';
19131 if (currentDate && prevMonth.valueOf() === currentDate) {
19132 clsName += ' active';
19135 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19136 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19137 clsName += ' disabled';
19140 fillMonths.cn.push({
19142 cls: 'day ' + clsName,
19143 html: prevMonth.getDate()
19146 prevMonth.setDate(prevMonth.getDate()+1);
19149 var currentYear = this.date && this.date.getUTCFullYear();
19150 var currentMonth = this.date && this.date.getUTCMonth();
19152 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19154 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19155 v.removeClass('active');
19157 if(currentYear === year && k === currentMonth){
19158 v.addClass('active');
19161 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19162 v.addClass('disabled');
19168 year = parseInt(year/10, 10) * 10;
19170 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19172 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19175 for (var i = -1; i < 11; i++) {
19176 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19178 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19186 showMode: function(dir)
19189 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19192 Roo.each(this.picker().select('>div',true).elements, function(v){
19193 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19196 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19201 if(this.isInline) {
19205 this.picker().removeClass(['bottom', 'top']);
19207 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19209 * place to the top of element!
19213 this.picker().addClass('top');
19214 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19219 this.picker().addClass('bottom');
19221 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19224 parseDate : function(value)
19226 if(!value || value instanceof Date){
19229 var v = Date.parseDate(value, this.format);
19230 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19231 v = Date.parseDate(value, 'Y-m-d');
19233 if(!v && this.altFormats){
19234 if(!this.altFormatsArray){
19235 this.altFormatsArray = this.altFormats.split("|");
19237 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19238 v = Date.parseDate(value, this.altFormatsArray[i]);
19244 formatDate : function(date, fmt)
19246 return (!date || !(date instanceof Date)) ?
19247 date : date.dateFormat(fmt || this.format);
19250 onFocus : function()
19252 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19256 onBlur : function()
19258 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19260 var d = this.inputEl().getValue();
19267 showPopup : function()
19269 this.picker().show();
19273 this.fireEvent('showpopup', this, this.date);
19276 hidePopup : function()
19278 if(this.isInline) {
19281 this.picker().hide();
19282 this.viewMode = this.startViewMode;
19285 this.fireEvent('hidepopup', this, this.date);
19289 onMousedown: function(e)
19291 e.stopPropagation();
19292 e.preventDefault();
19297 Roo.bootstrap.DateField.superclass.keyup.call(this);
19301 setValue: function(v)
19303 if(this.fireEvent('beforeselect', this, v) !== false){
19304 var d = new Date(this.parseDate(v) ).clearTime();
19306 if(isNaN(d.getTime())){
19307 this.date = this.viewDate = '';
19308 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19312 v = this.formatDate(d);
19314 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19316 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19320 this.fireEvent('select', this, this.date);
19324 getValue: function()
19326 return this.formatDate(this.date);
19329 fireKey: function(e)
19331 if (!this.picker().isVisible()){
19332 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19338 var dateChanged = false,
19340 newDate, newViewDate;
19345 e.preventDefault();
19349 if (!this.keyboardNavigation) {
19352 dir = e.keyCode == 37 ? -1 : 1;
19355 newDate = this.moveYear(this.date, dir);
19356 newViewDate = this.moveYear(this.viewDate, dir);
19357 } else if (e.shiftKey){
19358 newDate = this.moveMonth(this.date, dir);
19359 newViewDate = this.moveMonth(this.viewDate, dir);
19361 newDate = new Date(this.date);
19362 newDate.setUTCDate(this.date.getUTCDate() + dir);
19363 newViewDate = new Date(this.viewDate);
19364 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19366 if (this.dateWithinRange(newDate)){
19367 this.date = newDate;
19368 this.viewDate = newViewDate;
19369 this.setValue(this.formatDate(this.date));
19371 e.preventDefault();
19372 dateChanged = true;
19377 if (!this.keyboardNavigation) {
19380 dir = e.keyCode == 38 ? -1 : 1;
19382 newDate = this.moveYear(this.date, dir);
19383 newViewDate = this.moveYear(this.viewDate, dir);
19384 } else if (e.shiftKey){
19385 newDate = this.moveMonth(this.date, dir);
19386 newViewDate = this.moveMonth(this.viewDate, dir);
19388 newDate = new Date(this.date);
19389 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19390 newViewDate = new Date(this.viewDate);
19391 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19393 if (this.dateWithinRange(newDate)){
19394 this.date = newDate;
19395 this.viewDate = newViewDate;
19396 this.setValue(this.formatDate(this.date));
19398 e.preventDefault();
19399 dateChanged = true;
19403 this.setValue(this.formatDate(this.date));
19405 e.preventDefault();
19408 this.setValue(this.formatDate(this.date));
19422 onClick: function(e)
19424 e.stopPropagation();
19425 e.preventDefault();
19427 var target = e.getTarget();
19429 if(target.nodeName.toLowerCase() === 'i'){
19430 target = Roo.get(target).dom.parentNode;
19433 var nodeName = target.nodeName;
19434 var className = target.className;
19435 var html = target.innerHTML;
19436 //Roo.log(nodeName);
19438 switch(nodeName.toLowerCase()) {
19440 switch(className) {
19446 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19447 switch(this.viewMode){
19449 this.viewDate = this.moveMonth(this.viewDate, dir);
19453 this.viewDate = this.moveYear(this.viewDate, dir);
19459 var date = new Date();
19460 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19462 this.setValue(this.formatDate(this.date));
19469 if (className.indexOf('disabled') < 0) {
19470 this.viewDate.setUTCDate(1);
19471 if (className.indexOf('month') > -1) {
19472 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19474 var year = parseInt(html, 10) || 0;
19475 this.viewDate.setUTCFullYear(year);
19479 if(this.singleMode){
19480 this.setValue(this.formatDate(this.viewDate));
19491 //Roo.log(className);
19492 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19493 var day = parseInt(html, 10) || 1;
19494 var year = this.viewDate.getUTCFullYear(),
19495 month = this.viewDate.getUTCMonth();
19497 if (className.indexOf('old') > -1) {
19504 } else if (className.indexOf('new') > -1) {
19512 //Roo.log([year,month,day]);
19513 this.date = this.UTCDate(year, month, day,0,0,0,0);
19514 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19516 //Roo.log(this.formatDate(this.date));
19517 this.setValue(this.formatDate(this.date));
19524 setStartDate: function(startDate)
19526 this.startDate = startDate || -Infinity;
19527 if (this.startDate !== -Infinity) {
19528 this.startDate = this.parseDate(this.startDate);
19531 this.updateNavArrows();
19534 setEndDate: function(endDate)
19536 this.endDate = endDate || Infinity;
19537 if (this.endDate !== Infinity) {
19538 this.endDate = this.parseDate(this.endDate);
19541 this.updateNavArrows();
19544 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19546 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19547 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19548 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19550 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19551 return parseInt(d, 10);
19554 this.updateNavArrows();
19557 updateNavArrows: function()
19559 if(this.singleMode){
19563 var d = new Date(this.viewDate),
19564 year = d.getUTCFullYear(),
19565 month = d.getUTCMonth();
19567 Roo.each(this.picker().select('.prev', true).elements, function(v){
19569 switch (this.viewMode) {
19572 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19578 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19585 Roo.each(this.picker().select('.next', true).elements, function(v){
19587 switch (this.viewMode) {
19590 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19596 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19604 moveMonth: function(date, dir)
19609 var new_date = new Date(date.valueOf()),
19610 day = new_date.getUTCDate(),
19611 month = new_date.getUTCMonth(),
19612 mag = Math.abs(dir),
19614 dir = dir > 0 ? 1 : -1;
19617 // If going back one month, make sure month is not current month
19618 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19620 return new_date.getUTCMonth() == month;
19622 // If going forward one month, make sure month is as expected
19623 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19625 return new_date.getUTCMonth() != new_month;
19627 new_month = month + dir;
19628 new_date.setUTCMonth(new_month);
19629 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19630 if (new_month < 0 || new_month > 11) {
19631 new_month = (new_month + 12) % 12;
19634 // For magnitudes >1, move one month at a time...
19635 for (var i=0; i<mag; i++) {
19636 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19637 new_date = this.moveMonth(new_date, dir);
19639 // ...then reset the day, keeping it in the new month
19640 new_month = new_date.getUTCMonth();
19641 new_date.setUTCDate(day);
19643 return new_month != new_date.getUTCMonth();
19646 // Common date-resetting loop -- if date is beyond end of month, make it
19649 new_date.setUTCDate(--day);
19650 new_date.setUTCMonth(new_month);
19655 moveYear: function(date, dir)
19657 return this.moveMonth(date, dir*12);
19660 dateWithinRange: function(date)
19662 return date >= this.startDate && date <= this.endDate;
19668 this.picker().remove();
19671 validateValue : function(value)
19673 if(this.getVisibilityEl().hasClass('hidden')){
19677 if(value.length < 1) {
19678 if(this.allowBlank){
19684 if(value.length < this.minLength){
19687 if(value.length > this.maxLength){
19691 var vt = Roo.form.VTypes;
19692 if(!vt[this.vtype](value, this)){
19696 if(typeof this.validator == "function"){
19697 var msg = this.validator(value);
19703 if(this.regex && !this.regex.test(value)){
19707 if(typeof(this.parseDate(value)) == 'undefined'){
19711 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19715 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19725 this.date = this.viewDate = '';
19727 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19732 Roo.apply(Roo.bootstrap.DateField, {
19743 html: '<i class="fa fa-arrow-left"/>'
19753 html: '<i class="fa fa-arrow-right"/>'
19795 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19796 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19797 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19798 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19799 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19812 navFnc: 'FullYear',
19817 navFnc: 'FullYear',
19822 Roo.apply(Roo.bootstrap.DateField, {
19826 cls: 'datepicker dropdown-menu roo-dynamic',
19830 cls: 'datepicker-days',
19834 cls: 'table-condensed',
19836 Roo.bootstrap.DateField.head,
19840 Roo.bootstrap.DateField.footer
19847 cls: 'datepicker-months',
19851 cls: 'table-condensed',
19853 Roo.bootstrap.DateField.head,
19854 Roo.bootstrap.DateField.content,
19855 Roo.bootstrap.DateField.footer
19862 cls: 'datepicker-years',
19866 cls: 'table-condensed',
19868 Roo.bootstrap.DateField.head,
19869 Roo.bootstrap.DateField.content,
19870 Roo.bootstrap.DateField.footer
19889 * @class Roo.bootstrap.TimeField
19890 * @extends Roo.bootstrap.Input
19891 * Bootstrap DateField class
19895 * Create a new TimeField
19896 * @param {Object} config The config object
19899 Roo.bootstrap.TimeField = function(config){
19900 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19904 * Fires when this field show.
19905 * @param {Roo.bootstrap.DateField} thisthis
19906 * @param {Mixed} date The date value
19911 * Fires when this field hide.
19912 * @param {Roo.bootstrap.DateField} this
19913 * @param {Mixed} date The date value
19918 * Fires when select a date.
19919 * @param {Roo.bootstrap.DateField} this
19920 * @param {Mixed} date The date value
19926 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19929 * @cfg {String} format
19930 * The default time format string which can be overriden for localization support. The format must be
19931 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19935 onRender: function(ct, position)
19938 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19940 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19942 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19944 this.pop = this.picker().select('>.datepicker-time',true).first();
19945 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19947 this.picker().on('mousedown', this.onMousedown, this);
19948 this.picker().on('click', this.onClick, this);
19950 this.picker().addClass('datepicker-dropdown');
19955 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19956 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19957 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19958 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19959 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19960 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19964 fireKey: function(e){
19965 if (!this.picker().isVisible()){
19966 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19972 e.preventDefault();
19980 this.onTogglePeriod();
19983 this.onIncrementMinutes();
19986 this.onDecrementMinutes();
19995 onClick: function(e) {
19996 e.stopPropagation();
19997 e.preventDefault();
20000 picker : function()
20002 return this.el.select('.datepicker', true).first();
20005 fillTime: function()
20007 var time = this.pop.select('tbody', true).first();
20009 time.dom.innerHTML = '';
20024 cls: 'hours-up glyphicon glyphicon-chevron-up'
20044 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20065 cls: 'timepicker-hour',
20080 cls: 'timepicker-minute',
20095 cls: 'btn btn-primary period',
20117 cls: 'hours-down glyphicon glyphicon-chevron-down'
20137 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20155 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20162 var hours = this.time.getHours();
20163 var minutes = this.time.getMinutes();
20176 hours = hours - 12;
20180 hours = '0' + hours;
20184 minutes = '0' + minutes;
20187 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20188 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20189 this.pop.select('button', true).first().dom.innerHTML = period;
20195 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20197 var cls = ['bottom'];
20199 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20206 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20211 this.picker().addClass(cls.join('-'));
20215 Roo.each(cls, function(c){
20217 _this.picker().setTop(_this.inputEl().getHeight());
20221 _this.picker().setTop(0 - _this.picker().getHeight());
20226 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20230 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20237 onFocus : function()
20239 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20243 onBlur : function()
20245 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20251 this.picker().show();
20256 this.fireEvent('show', this, this.date);
20261 this.picker().hide();
20264 this.fireEvent('hide', this, this.date);
20267 setTime : function()
20270 this.setValue(this.time.format(this.format));
20272 this.fireEvent('select', this, this.date);
20277 onMousedown: function(e){
20278 e.stopPropagation();
20279 e.preventDefault();
20282 onIncrementHours: function()
20284 Roo.log('onIncrementHours');
20285 this.time = this.time.add(Date.HOUR, 1);
20290 onDecrementHours: function()
20292 Roo.log('onDecrementHours');
20293 this.time = this.time.add(Date.HOUR, -1);
20297 onIncrementMinutes: function()
20299 Roo.log('onIncrementMinutes');
20300 this.time = this.time.add(Date.MINUTE, 1);
20304 onDecrementMinutes: function()
20306 Roo.log('onDecrementMinutes');
20307 this.time = this.time.add(Date.MINUTE, -1);
20311 onTogglePeriod: function()
20313 Roo.log('onTogglePeriod');
20314 this.time = this.time.add(Date.HOUR, 12);
20321 Roo.apply(Roo.bootstrap.TimeField, {
20351 cls: 'btn btn-info ok',
20363 Roo.apply(Roo.bootstrap.TimeField, {
20367 cls: 'datepicker dropdown-menu',
20371 cls: 'datepicker-time',
20375 cls: 'table-condensed',
20377 Roo.bootstrap.TimeField.content,
20378 Roo.bootstrap.TimeField.footer
20397 * @class Roo.bootstrap.MonthField
20398 * @extends Roo.bootstrap.Input
20399 * Bootstrap MonthField class
20401 * @cfg {String} language default en
20404 * Create a new MonthField
20405 * @param {Object} config The config object
20408 Roo.bootstrap.MonthField = function(config){
20409 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20414 * Fires when this field show.
20415 * @param {Roo.bootstrap.MonthField} this
20416 * @param {Mixed} date The date value
20421 * Fires when this field hide.
20422 * @param {Roo.bootstrap.MonthField} this
20423 * @param {Mixed} date The date value
20428 * Fires when select a date.
20429 * @param {Roo.bootstrap.MonthField} this
20430 * @param {String} oldvalue The old value
20431 * @param {String} newvalue The new value
20437 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20439 onRender: function(ct, position)
20442 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20444 this.language = this.language || 'en';
20445 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20446 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20448 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20449 this.isInline = false;
20450 this.isInput = true;
20451 this.component = this.el.select('.add-on', true).first() || false;
20452 this.component = (this.component && this.component.length === 0) ? false : this.component;
20453 this.hasInput = this.component && this.inputEL().length;
20455 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20457 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20459 this.picker().on('mousedown', this.onMousedown, this);
20460 this.picker().on('click', this.onClick, this);
20462 this.picker().addClass('datepicker-dropdown');
20464 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20465 v.setStyle('width', '189px');
20472 if(this.isInline) {
20478 setValue: function(v, suppressEvent)
20480 var o = this.getValue();
20482 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20486 if(suppressEvent !== true){
20487 this.fireEvent('select', this, o, v);
20492 getValue: function()
20497 onClick: function(e)
20499 e.stopPropagation();
20500 e.preventDefault();
20502 var target = e.getTarget();
20504 if(target.nodeName.toLowerCase() === 'i'){
20505 target = Roo.get(target).dom.parentNode;
20508 var nodeName = target.nodeName;
20509 var className = target.className;
20510 var html = target.innerHTML;
20512 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20516 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20518 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20524 picker : function()
20526 return this.pickerEl;
20529 fillMonths: function()
20532 var months = this.picker().select('>.datepicker-months td', true).first();
20534 months.dom.innerHTML = '';
20540 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20543 months.createChild(month);
20552 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20553 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20556 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20557 e.removeClass('active');
20559 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20560 e.addClass('active');
20567 if(this.isInline) {
20571 this.picker().removeClass(['bottom', 'top']);
20573 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20575 * place to the top of element!
20579 this.picker().addClass('top');
20580 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20585 this.picker().addClass('bottom');
20587 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20590 onFocus : function()
20592 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20596 onBlur : function()
20598 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20600 var d = this.inputEl().getValue();
20609 this.picker().show();
20610 this.picker().select('>.datepicker-months', true).first().show();
20614 this.fireEvent('show', this, this.date);
20619 if(this.isInline) {
20622 this.picker().hide();
20623 this.fireEvent('hide', this, this.date);
20627 onMousedown: function(e)
20629 e.stopPropagation();
20630 e.preventDefault();
20635 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20639 fireKey: function(e)
20641 if (!this.picker().isVisible()){
20642 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20653 e.preventDefault();
20657 dir = e.keyCode == 37 ? -1 : 1;
20659 this.vIndex = this.vIndex + dir;
20661 if(this.vIndex < 0){
20665 if(this.vIndex > 11){
20669 if(isNaN(this.vIndex)){
20673 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20679 dir = e.keyCode == 38 ? -1 : 1;
20681 this.vIndex = this.vIndex + dir * 4;
20683 if(this.vIndex < 0){
20687 if(this.vIndex > 11){
20691 if(isNaN(this.vIndex)){
20695 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20700 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20701 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20705 e.preventDefault();
20708 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20709 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20725 this.picker().remove();
20730 Roo.apply(Roo.bootstrap.MonthField, {
20749 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20750 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20755 Roo.apply(Roo.bootstrap.MonthField, {
20759 cls: 'datepicker dropdown-menu roo-dynamic',
20763 cls: 'datepicker-months',
20767 cls: 'table-condensed',
20769 Roo.bootstrap.DateField.content
20789 * @class Roo.bootstrap.CheckBox
20790 * @extends Roo.bootstrap.Input
20791 * Bootstrap CheckBox class
20793 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20794 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20795 * @cfg {String} boxLabel The text that appears beside the checkbox
20796 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20797 * @cfg {Boolean} checked initnal the element
20798 * @cfg {Boolean} inline inline the element (default false)
20799 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20800 * @cfg {String} tooltip label tooltip
20803 * Create a new CheckBox
20804 * @param {Object} config The config object
20807 Roo.bootstrap.CheckBox = function(config){
20808 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20813 * Fires when the element is checked or unchecked.
20814 * @param {Roo.bootstrap.CheckBox} this This input
20815 * @param {Boolean} checked The new checked value
20820 * Fires when the element is click.
20821 * @param {Roo.bootstrap.CheckBox} this This input
20828 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20830 inputType: 'checkbox',
20839 getAutoCreate : function()
20841 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20847 cfg.cls = 'form-group ' + this.inputType; //input-group
20850 cfg.cls += ' ' + this.inputType + '-inline';
20856 type : this.inputType,
20857 value : this.inputValue,
20858 cls : 'roo-' + this.inputType, //'form-box',
20859 placeholder : this.placeholder || ''
20863 if(this.inputType != 'radio'){
20867 cls : 'roo-hidden-value',
20868 value : this.checked ? this.inputValue : this.valueOff
20873 if (this.weight) { // Validity check?
20874 cfg.cls += " " + this.inputType + "-" + this.weight;
20877 if (this.disabled) {
20878 input.disabled=true;
20882 input.checked = this.checked;
20887 input.name = this.name;
20889 if(this.inputType != 'radio'){
20890 hidden.name = this.name;
20891 input.name = '_hidden_' + this.name;
20896 input.cls += ' input-' + this.size;
20901 ['xs','sm','md','lg'].map(function(size){
20902 if (settings[size]) {
20903 cfg.cls += ' col-' + size + '-' + settings[size];
20907 var inputblock = input;
20909 if (this.before || this.after) {
20912 cls : 'input-group',
20917 inputblock.cn.push({
20919 cls : 'input-group-addon',
20924 inputblock.cn.push(input);
20926 if(this.inputType != 'radio'){
20927 inputblock.cn.push(hidden);
20931 inputblock.cn.push({
20933 cls : 'input-group-addon',
20940 if (align ==='left' && this.fieldLabel.length) {
20941 // Roo.log("left and has label");
20946 cls : 'control-label',
20947 html : this.fieldLabel
20957 if(this.labelWidth > 12){
20958 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20961 if(this.labelWidth < 13 && this.labelmd == 0){
20962 this.labelmd = this.labelWidth;
20965 if(this.labellg > 0){
20966 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20967 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20970 if(this.labelmd > 0){
20971 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20972 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20975 if(this.labelsm > 0){
20976 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20977 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20980 if(this.labelxs > 0){
20981 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20982 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20985 } else if ( this.fieldLabel.length) {
20986 // Roo.log(" label");
20990 tag: this.boxLabel ? 'span' : 'label',
20992 cls: 'control-label box-input-label',
20993 //cls : 'input-group-addon',
20994 html : this.fieldLabel
21003 // Roo.log(" no label && no align");
21004 cfg.cn = [ inputblock ] ;
21010 var boxLabelCfg = {
21012 //'for': id, // box label is handled by onclick - so no for...
21014 html: this.boxLabel
21018 boxLabelCfg.tooltip = this.tooltip;
21021 cfg.cn.push(boxLabelCfg);
21024 if(this.inputType != 'radio'){
21025 cfg.cn.push(hidden);
21033 * return the real input element.
21035 inputEl: function ()
21037 return this.el.select('input.roo-' + this.inputType,true).first();
21039 hiddenEl: function ()
21041 return this.el.select('input.roo-hidden-value',true).first();
21044 labelEl: function()
21046 return this.el.select('label.control-label',true).first();
21048 /* depricated... */
21052 return this.labelEl();
21055 boxLabelEl: function()
21057 return this.el.select('label.box-label',true).first();
21060 initEvents : function()
21062 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21064 this.inputEl().on('click', this.onClick, this);
21066 if (this.boxLabel) {
21067 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21070 this.startValue = this.getValue();
21073 Roo.bootstrap.CheckBox.register(this);
21077 onClick : function(e)
21079 if(this.fireEvent('click', this, e) !== false){
21080 this.setChecked(!this.checked);
21085 setChecked : function(state,suppressEvent)
21087 this.startValue = this.getValue();
21089 if(this.inputType == 'radio'){
21091 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21092 e.dom.checked = false;
21095 this.inputEl().dom.checked = true;
21097 this.inputEl().dom.value = this.inputValue;
21099 if(suppressEvent !== true){
21100 this.fireEvent('check', this, true);
21108 this.checked = state;
21110 this.inputEl().dom.checked = state;
21113 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21115 if(suppressEvent !== true){
21116 this.fireEvent('check', this, state);
21122 getValue : function()
21124 if(this.inputType == 'radio'){
21125 return this.getGroupValue();
21128 return this.hiddenEl().dom.value;
21132 getGroupValue : function()
21134 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21138 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21141 setValue : function(v,suppressEvent)
21143 if(this.inputType == 'radio'){
21144 this.setGroupValue(v, suppressEvent);
21148 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21153 setGroupValue : function(v, suppressEvent)
21155 this.startValue = this.getValue();
21157 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21158 e.dom.checked = false;
21160 if(e.dom.value == v){
21161 e.dom.checked = true;
21165 if(suppressEvent !== true){
21166 this.fireEvent('check', this, true);
21174 validate : function()
21176 if(this.getVisibilityEl().hasClass('hidden')){
21182 (this.inputType == 'radio' && this.validateRadio()) ||
21183 (this.inputType == 'checkbox' && this.validateCheckbox())
21189 this.markInvalid();
21193 validateRadio : function()
21195 if(this.getVisibilityEl().hasClass('hidden')){
21199 if(this.allowBlank){
21205 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21206 if(!e.dom.checked){
21218 validateCheckbox : function()
21221 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21222 //return (this.getValue() == this.inputValue) ? true : false;
21225 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21233 for(var i in group){
21234 if(group[i].el.isVisible(true)){
21242 for(var i in group){
21247 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21254 * Mark this field as valid
21256 markValid : function()
21260 this.fireEvent('valid', this);
21262 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21265 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21272 if(this.inputType == 'radio'){
21273 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21274 var fg = e.findParent('.form-group', false, true);
21275 if (Roo.bootstrap.version == 3) {
21276 fg.removeClass([_this.invalidClass, _this.validClass]);
21277 fg.addClass(_this.validClass);
21279 fg.removeClass(['is-valid', 'is-invalid']);
21280 fg.addClass('is-valid');
21288 var fg = this.el.findParent('.form-group', false, true);
21289 if (Roo.bootstrap.version == 3) {
21290 fg.removeClass([this.invalidClass, this.validClass]);
21291 fg.addClass(this.validClass);
21293 fg.removeClass(['is-valid', 'is-invalid']);
21294 fg.addClass('is-valid');
21299 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21305 for(var i in group){
21306 var fg = group[i].el.findParent('.form-group', false, true);
21307 if (Roo.bootstrap.version == 3) {
21308 fg.removeClass([this.invalidClass, this.validClass]);
21309 fg.addClass(this.validClass);
21311 fg.removeClass(['is-valid', 'is-invalid']);
21312 fg.addClass('is-valid');
21318 * Mark this field as invalid
21319 * @param {String} msg The validation message
21321 markInvalid : function(msg)
21323 if(this.allowBlank){
21329 this.fireEvent('invalid', this, msg);
21331 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21334 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21338 label.markInvalid();
21341 if(this.inputType == 'radio'){
21343 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21344 var fg = e.findParent('.form-group', false, true);
21345 if (Roo.bootstrap.version == 3) {
21346 fg.removeClass([_this.invalidClass, _this.validClass]);
21347 fg.addClass(_this.invalidClass);
21349 fg.removeClass(['is-invalid', 'is-valid']);
21350 fg.addClass('is-invalid');
21358 var fg = this.el.findParent('.form-group', false, true);
21359 if (Roo.bootstrap.version == 3) {
21360 fg.removeClass([_this.invalidClass, _this.validClass]);
21361 fg.addClass(_this.invalidClass);
21363 fg.removeClass(['is-invalid', 'is-valid']);
21364 fg.addClass('is-invalid');
21369 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21375 for(var i in group){
21376 var fg = group[i].el.findParent('.form-group', false, true);
21377 if (Roo.bootstrap.version == 3) {
21378 fg.removeClass([_this.invalidClass, _this.validClass]);
21379 fg.addClass(_this.invalidClass);
21381 fg.removeClass(['is-invalid', 'is-valid']);
21382 fg.addClass('is-invalid');
21388 clearInvalid : function()
21390 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21392 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21394 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21396 if (label && label.iconEl) {
21397 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21398 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21402 disable : function()
21404 if(this.inputType != 'radio'){
21405 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21412 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21413 _this.getActionEl().addClass(this.disabledClass);
21414 e.dom.disabled = true;
21418 this.disabled = true;
21419 this.fireEvent("disable", this);
21423 enable : function()
21425 if(this.inputType != 'radio'){
21426 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21433 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21434 _this.getActionEl().removeClass(this.disabledClass);
21435 e.dom.disabled = false;
21439 this.disabled = false;
21440 this.fireEvent("enable", this);
21444 setBoxLabel : function(v)
21449 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21455 Roo.apply(Roo.bootstrap.CheckBox, {
21460 * register a CheckBox Group
21461 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21463 register : function(checkbox)
21465 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21466 this.groups[checkbox.groupId] = {};
21469 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21473 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21477 * fetch a CheckBox Group based on the group ID
21478 * @param {string} the group ID
21479 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21481 get: function(groupId) {
21482 if (typeof(this.groups[groupId]) == 'undefined') {
21486 return this.groups[groupId] ;
21499 * @class Roo.bootstrap.Radio
21500 * @extends Roo.bootstrap.Component
21501 * Bootstrap Radio class
21502 * @cfg {String} boxLabel - the label associated
21503 * @cfg {String} value - the value of radio
21506 * Create a new Radio
21507 * @param {Object} config The config object
21509 Roo.bootstrap.Radio = function(config){
21510 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21514 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21520 getAutoCreate : function()
21524 cls : 'form-group radio',
21529 html : this.boxLabel
21537 initEvents : function()
21539 this.parent().register(this);
21541 this.el.on('click', this.onClick, this);
21545 onClick : function(e)
21547 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21548 this.setChecked(true);
21552 setChecked : function(state, suppressEvent)
21554 this.parent().setValue(this.value, suppressEvent);
21558 setBoxLabel : function(v)
21563 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21578 * @class Roo.bootstrap.SecurePass
21579 * @extends Roo.bootstrap.Input
21580 * Bootstrap SecurePass class
21584 * Create a new SecurePass
21585 * @param {Object} config The config object
21588 Roo.bootstrap.SecurePass = function (config) {
21589 // these go here, so the translation tool can replace them..
21591 PwdEmpty: "Please type a password, and then retype it to confirm.",
21592 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21593 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21594 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21595 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21596 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21597 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21598 TooWeak: "Your password is Too Weak."
21600 this.meterLabel = "Password strength:";
21601 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21602 this.meterClass = [
21603 "roo-password-meter-tooweak",
21604 "roo-password-meter-weak",
21605 "roo-password-meter-medium",
21606 "roo-password-meter-strong",
21607 "roo-password-meter-grey"
21612 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21615 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21617 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21619 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21620 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21621 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21622 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21623 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21624 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21625 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21635 * @cfg {String/Object} Label for the strength meter (defaults to
21636 * 'Password strength:')
21641 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21642 * ['Weak', 'Medium', 'Strong'])
21645 pwdStrengths: false,
21658 initEvents: function ()
21660 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21662 if (this.el.is('input[type=password]') && Roo.isSafari) {
21663 this.el.on('keydown', this.SafariOnKeyDown, this);
21666 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21669 onRender: function (ct, position)
21671 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21672 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21673 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21675 this.trigger.createChild({
21680 cls: 'roo-password-meter-grey col-xs-12',
21683 //width: this.meterWidth + 'px'
21687 cls: 'roo-password-meter-text'
21693 if (this.hideTrigger) {
21694 this.trigger.setDisplayed(false);
21696 this.setSize(this.width || '', this.height || '');
21699 onDestroy: function ()
21701 if (this.trigger) {
21702 this.trigger.removeAllListeners();
21703 this.trigger.remove();
21706 this.wrap.remove();
21708 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21711 checkStrength: function ()
21713 var pwd = this.inputEl().getValue();
21714 if (pwd == this._lastPwd) {
21719 if (this.ClientSideStrongPassword(pwd)) {
21721 } else if (this.ClientSideMediumPassword(pwd)) {
21723 } else if (this.ClientSideWeakPassword(pwd)) {
21729 Roo.log('strength1: ' + strength);
21731 //var pm = this.trigger.child('div/div/div').dom;
21732 var pm = this.trigger.child('div/div');
21733 pm.removeClass(this.meterClass);
21734 pm.addClass(this.meterClass[strength]);
21737 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21739 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21741 this._lastPwd = pwd;
21745 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21747 this._lastPwd = '';
21749 var pm = this.trigger.child('div/div');
21750 pm.removeClass(this.meterClass);
21751 pm.addClass('roo-password-meter-grey');
21754 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21757 this.inputEl().dom.type='password';
21760 validateValue: function (value)
21763 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21766 if (value.length == 0) {
21767 if (this.allowBlank) {
21768 this.clearInvalid();
21772 this.markInvalid(this.errors.PwdEmpty);
21773 this.errorMsg = this.errors.PwdEmpty;
21781 if ('[\x21-\x7e]*'.match(value)) {
21782 this.markInvalid(this.errors.PwdBadChar);
21783 this.errorMsg = this.errors.PwdBadChar;
21786 if (value.length < 6) {
21787 this.markInvalid(this.errors.PwdShort);
21788 this.errorMsg = this.errors.PwdShort;
21791 if (value.length > 16) {
21792 this.markInvalid(this.errors.PwdLong);
21793 this.errorMsg = this.errors.PwdLong;
21797 if (this.ClientSideStrongPassword(value)) {
21799 } else if (this.ClientSideMediumPassword(value)) {
21801 } else if (this.ClientSideWeakPassword(value)) {
21808 if (strength < 2) {
21809 //this.markInvalid(this.errors.TooWeak);
21810 this.errorMsg = this.errors.TooWeak;
21815 console.log('strength2: ' + strength);
21817 //var pm = this.trigger.child('div/div/div').dom;
21819 var pm = this.trigger.child('div/div');
21820 pm.removeClass(this.meterClass);
21821 pm.addClass(this.meterClass[strength]);
21823 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21825 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21827 this.errorMsg = '';
21831 CharacterSetChecks: function (type)
21834 this.fResult = false;
21837 isctype: function (character, type)
21840 case this.kCapitalLetter:
21841 if (character >= 'A' && character <= 'Z') {
21846 case this.kSmallLetter:
21847 if (character >= 'a' && character <= 'z') {
21853 if (character >= '0' && character <= '9') {
21858 case this.kPunctuation:
21859 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21870 IsLongEnough: function (pwd, size)
21872 return !(pwd == null || isNaN(size) || pwd.length < size);
21875 SpansEnoughCharacterSets: function (word, nb)
21877 if (!this.IsLongEnough(word, nb))
21882 var characterSetChecks = new Array(
21883 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21884 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21887 for (var index = 0; index < word.length; ++index) {
21888 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21889 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21890 characterSetChecks[nCharSet].fResult = true;
21897 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21898 if (characterSetChecks[nCharSet].fResult) {
21903 if (nCharSets < nb) {
21909 ClientSideStrongPassword: function (pwd)
21911 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21914 ClientSideMediumPassword: function (pwd)
21916 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21919 ClientSideWeakPassword: function (pwd)
21921 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21924 })//<script type="text/javascript">
21927 * Based Ext JS Library 1.1.1
21928 * Copyright(c) 2006-2007, Ext JS, LLC.
21934 * @class Roo.HtmlEditorCore
21935 * @extends Roo.Component
21936 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21938 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21941 Roo.HtmlEditorCore = function(config){
21944 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21949 * @event initialize
21950 * Fires when the editor is fully initialized (including the iframe)
21951 * @param {Roo.HtmlEditorCore} this
21956 * Fires when the editor is first receives the focus. Any insertion must wait
21957 * until after this event.
21958 * @param {Roo.HtmlEditorCore} this
21962 * @event beforesync
21963 * Fires before the textarea is updated with content from the editor iframe. Return false
21964 * to cancel the sync.
21965 * @param {Roo.HtmlEditorCore} this
21966 * @param {String} html
21970 * @event beforepush
21971 * Fires before the iframe editor is updated with content from the textarea. Return false
21972 * to cancel the push.
21973 * @param {Roo.HtmlEditorCore} this
21974 * @param {String} html
21979 * Fires when the textarea is updated with content from the editor iframe.
21980 * @param {Roo.HtmlEditorCore} this
21981 * @param {String} html
21986 * Fires when the iframe editor is updated with content from the textarea.
21987 * @param {Roo.HtmlEditorCore} this
21988 * @param {String} html
21993 * @event editorevent
21994 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21995 * @param {Roo.HtmlEditorCore} this
22001 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22003 // defaults : white / black...
22004 this.applyBlacklists();
22011 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22015 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22021 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22026 * @cfg {Number} height (in pixels)
22030 * @cfg {Number} width (in pixels)
22035 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22038 stylesheets: false,
22043 // private properties
22044 validationEvent : false,
22046 initialized : false,
22048 sourceEditMode : false,
22049 onFocus : Roo.emptyFn,
22051 hideMode:'offsets',
22055 // blacklist + whitelisted elements..
22062 * Protected method that will not generally be called directly. It
22063 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22064 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22066 getDocMarkup : function(){
22070 // inherit styels from page...??
22071 if (this.stylesheets === false) {
22073 Roo.get(document.head).select('style').each(function(node) {
22074 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22077 Roo.get(document.head).select('link').each(function(node) {
22078 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22081 } else if (!this.stylesheets.length) {
22083 st = '<style type="text/css">' +
22084 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22087 st = '<style type="text/css">' +
22092 st += '<style type="text/css">' +
22093 'IMG { cursor: pointer } ' +
22096 var cls = 'roo-htmleditor-body';
22098 if(this.bodyCls.length){
22099 cls += ' ' + this.bodyCls;
22102 return '<html><head>' + st +
22103 //<style type="text/css">' +
22104 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22106 ' </head><body class="' + cls + '"></body></html>';
22110 onRender : function(ct, position)
22113 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22114 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22117 this.el.dom.style.border = '0 none';
22118 this.el.dom.setAttribute('tabIndex', -1);
22119 this.el.addClass('x-hidden hide');
22123 if(Roo.isIE){ // fix IE 1px bogus margin
22124 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22128 this.frameId = Roo.id();
22132 var iframe = this.owner.wrap.createChild({
22134 cls: 'form-control', // bootstrap..
22136 name: this.frameId,
22137 frameBorder : 'no',
22138 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22143 this.iframe = iframe.dom;
22145 this.assignDocWin();
22147 this.doc.designMode = 'on';
22150 this.doc.write(this.getDocMarkup());
22154 var task = { // must defer to wait for browser to be ready
22156 //console.log("run task?" + this.doc.readyState);
22157 this.assignDocWin();
22158 if(this.doc.body || this.doc.readyState == 'complete'){
22160 this.doc.designMode="on";
22164 Roo.TaskMgr.stop(task);
22165 this.initEditor.defer(10, this);
22172 Roo.TaskMgr.start(task);
22177 onResize : function(w, h)
22179 Roo.log('resize: ' +w + ',' + h );
22180 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22184 if(typeof w == 'number'){
22186 this.iframe.style.width = w + 'px';
22188 if(typeof h == 'number'){
22190 this.iframe.style.height = h + 'px';
22192 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22199 * Toggles the editor between standard and source edit mode.
22200 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22202 toggleSourceEdit : function(sourceEditMode){
22204 this.sourceEditMode = sourceEditMode === true;
22206 if(this.sourceEditMode){
22208 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22211 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22212 //this.iframe.className = '';
22215 //this.setSize(this.owner.wrap.getSize());
22216 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22223 * Protected method that will not generally be called directly. If you need/want
22224 * custom HTML cleanup, this is the method you should override.
22225 * @param {String} html The HTML to be cleaned
22226 * return {String} The cleaned HTML
22228 cleanHtml : function(html){
22229 html = String(html);
22230 if(html.length > 5){
22231 if(Roo.isSafari){ // strip safari nonsense
22232 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22235 if(html == ' '){
22242 * HTML Editor -> Textarea
22243 * Protected method that will not generally be called directly. Syncs the contents
22244 * of the editor iframe with the textarea.
22246 syncValue : function(){
22247 if(this.initialized){
22248 var bd = (this.doc.body || this.doc.documentElement);
22249 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22250 var html = bd.innerHTML;
22252 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22253 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22255 html = '<div style="'+m[0]+'">' + html + '</div>';
22258 html = this.cleanHtml(html);
22259 // fix up the special chars.. normaly like back quotes in word...
22260 // however we do not want to do this with chinese..
22261 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22262 var cc = b.charCodeAt();
22264 (cc >= 0x4E00 && cc < 0xA000 ) ||
22265 (cc >= 0x3400 && cc < 0x4E00 ) ||
22266 (cc >= 0xf900 && cc < 0xfb00 )
22272 if(this.owner.fireEvent('beforesync', this, html) !== false){
22273 this.el.dom.value = html;
22274 this.owner.fireEvent('sync', this, html);
22280 * Protected method that will not generally be called directly. Pushes the value of the textarea
22281 * into the iframe editor.
22283 pushValue : function(){
22284 if(this.initialized){
22285 var v = this.el.dom.value.trim();
22287 // if(v.length < 1){
22291 if(this.owner.fireEvent('beforepush', this, v) !== false){
22292 var d = (this.doc.body || this.doc.documentElement);
22294 this.cleanUpPaste();
22295 this.el.dom.value = d.innerHTML;
22296 this.owner.fireEvent('push', this, v);
22302 deferFocus : function(){
22303 this.focus.defer(10, this);
22307 focus : function(){
22308 if(this.win && !this.sourceEditMode){
22315 assignDocWin: function()
22317 var iframe = this.iframe;
22320 this.doc = iframe.contentWindow.document;
22321 this.win = iframe.contentWindow;
22323 // if (!Roo.get(this.frameId)) {
22326 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22327 // this.win = Roo.get(this.frameId).dom.contentWindow;
22329 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22333 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22334 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22339 initEditor : function(){
22340 //console.log("INIT EDITOR");
22341 this.assignDocWin();
22345 this.doc.designMode="on";
22347 this.doc.write(this.getDocMarkup());
22350 var dbody = (this.doc.body || this.doc.documentElement);
22351 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22352 // this copies styles from the containing element into thsi one..
22353 // not sure why we need all of this..
22354 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22356 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22357 //ss['background-attachment'] = 'fixed'; // w3c
22358 dbody.bgProperties = 'fixed'; // ie
22359 //Roo.DomHelper.applyStyles(dbody, ss);
22360 Roo.EventManager.on(this.doc, {
22361 //'mousedown': this.onEditorEvent,
22362 'mouseup': this.onEditorEvent,
22363 'dblclick': this.onEditorEvent,
22364 'click': this.onEditorEvent,
22365 'keyup': this.onEditorEvent,
22370 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22372 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22373 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22375 this.initialized = true;
22377 this.owner.fireEvent('initialize', this);
22382 onDestroy : function(){
22388 //for (var i =0; i < this.toolbars.length;i++) {
22389 // // fixme - ask toolbars for heights?
22390 // this.toolbars[i].onDestroy();
22393 //this.wrap.dom.innerHTML = '';
22394 //this.wrap.remove();
22399 onFirstFocus : function(){
22401 this.assignDocWin();
22404 this.activated = true;
22407 if(Roo.isGecko){ // prevent silly gecko errors
22409 var s = this.win.getSelection();
22410 if(!s.focusNode || s.focusNode.nodeType != 3){
22411 var r = s.getRangeAt(0);
22412 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22417 this.execCmd('useCSS', true);
22418 this.execCmd('styleWithCSS', false);
22421 this.owner.fireEvent('activate', this);
22425 adjustFont: function(btn){
22426 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22427 //if(Roo.isSafari){ // safari
22430 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22431 if(Roo.isSafari){ // safari
22432 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22433 v = (v < 10) ? 10 : v;
22434 v = (v > 48) ? 48 : v;
22435 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22440 v = Math.max(1, v+adjust);
22442 this.execCmd('FontSize', v );
22445 onEditorEvent : function(e)
22447 this.owner.fireEvent('editorevent', this, e);
22448 // this.updateToolbar();
22449 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22452 insertTag : function(tg)
22454 // could be a bit smarter... -> wrap the current selected tRoo..
22455 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22457 range = this.createRange(this.getSelection());
22458 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22459 wrappingNode.appendChild(range.extractContents());
22460 range.insertNode(wrappingNode);
22467 this.execCmd("formatblock", tg);
22471 insertText : function(txt)
22475 var range = this.createRange();
22476 range.deleteContents();
22477 //alert(Sender.getAttribute('label'));
22479 range.insertNode(this.doc.createTextNode(txt));
22485 * Executes a Midas editor command on the editor document and performs necessary focus and
22486 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22487 * @param {String} cmd The Midas command
22488 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22490 relayCmd : function(cmd, value){
22492 this.execCmd(cmd, value);
22493 this.owner.fireEvent('editorevent', this);
22494 //this.updateToolbar();
22495 this.owner.deferFocus();
22499 * Executes a Midas editor command directly on the editor document.
22500 * For visual commands, you should use {@link #relayCmd} instead.
22501 * <b>This should only be called after the editor is initialized.</b>
22502 * @param {String} cmd The Midas command
22503 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22505 execCmd : function(cmd, value){
22506 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22513 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22515 * @param {String} text | dom node..
22517 insertAtCursor : function(text)
22520 if(!this.activated){
22526 var r = this.doc.selection.createRange();
22537 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22541 // from jquery ui (MIT licenced)
22543 var win = this.win;
22545 if (win.getSelection && win.getSelection().getRangeAt) {
22546 range = win.getSelection().getRangeAt(0);
22547 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22548 range.insertNode(node);
22549 } else if (win.document.selection && win.document.selection.createRange) {
22550 // no firefox support
22551 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22552 win.document.selection.createRange().pasteHTML(txt);
22554 // no firefox support
22555 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22556 this.execCmd('InsertHTML', txt);
22565 mozKeyPress : function(e){
22567 var c = e.getCharCode(), cmd;
22570 c = String.fromCharCode(c).toLowerCase();
22584 this.cleanUpPaste.defer(100, this);
22592 e.preventDefault();
22600 fixKeys : function(){ // load time branching for fastest keydown performance
22602 return function(e){
22603 var k = e.getKey(), r;
22606 r = this.doc.selection.createRange();
22609 r.pasteHTML('    ');
22616 r = this.doc.selection.createRange();
22618 var target = r.parentElement();
22619 if(!target || target.tagName.toLowerCase() != 'li'){
22621 r.pasteHTML('<br />');
22627 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22628 this.cleanUpPaste.defer(100, this);
22634 }else if(Roo.isOpera){
22635 return function(e){
22636 var k = e.getKey();
22640 this.execCmd('InsertHTML','    ');
22643 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22644 this.cleanUpPaste.defer(100, this);
22649 }else if(Roo.isSafari){
22650 return function(e){
22651 var k = e.getKey();
22655 this.execCmd('InsertText','\t');
22659 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22660 this.cleanUpPaste.defer(100, this);
22668 getAllAncestors: function()
22670 var p = this.getSelectedNode();
22673 a.push(p); // push blank onto stack..
22674 p = this.getParentElement();
22678 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22682 a.push(this.doc.body);
22686 lastSelNode : false,
22689 getSelection : function()
22691 this.assignDocWin();
22692 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22695 getSelectedNode: function()
22697 // this may only work on Gecko!!!
22699 // should we cache this!!!!
22704 var range = this.createRange(this.getSelection()).cloneRange();
22707 var parent = range.parentElement();
22709 var testRange = range.duplicate();
22710 testRange.moveToElementText(parent);
22711 if (testRange.inRange(range)) {
22714 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22717 parent = parent.parentElement;
22722 // is ancestor a text element.
22723 var ac = range.commonAncestorContainer;
22724 if (ac.nodeType == 3) {
22725 ac = ac.parentNode;
22728 var ar = ac.childNodes;
22731 var other_nodes = [];
22732 var has_other_nodes = false;
22733 for (var i=0;i<ar.length;i++) {
22734 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22737 // fullly contained node.
22739 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22744 // probably selected..
22745 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22746 other_nodes.push(ar[i]);
22750 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22755 has_other_nodes = true;
22757 if (!nodes.length && other_nodes.length) {
22758 nodes= other_nodes;
22760 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22766 createRange: function(sel)
22768 // this has strange effects when using with
22769 // top toolbar - not sure if it's a great idea.
22770 //this.editor.contentWindow.focus();
22771 if (typeof sel != "undefined") {
22773 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22775 return this.doc.createRange();
22778 return this.doc.createRange();
22781 getParentElement: function()
22784 this.assignDocWin();
22785 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22787 var range = this.createRange(sel);
22790 var p = range.commonAncestorContainer;
22791 while (p.nodeType == 3) { // text node
22802 * Range intersection.. the hard stuff...
22806 * [ -- selected range --- ]
22810 * if end is before start or hits it. fail.
22811 * if start is after end or hits it fail.
22813 * if either hits (but other is outside. - then it's not
22819 // @see http://www.thismuchiknow.co.uk/?p=64.
22820 rangeIntersectsNode : function(range, node)
22822 var nodeRange = node.ownerDocument.createRange();
22824 nodeRange.selectNode(node);
22826 nodeRange.selectNodeContents(node);
22829 var rangeStartRange = range.cloneRange();
22830 rangeStartRange.collapse(true);
22832 var rangeEndRange = range.cloneRange();
22833 rangeEndRange.collapse(false);
22835 var nodeStartRange = nodeRange.cloneRange();
22836 nodeStartRange.collapse(true);
22838 var nodeEndRange = nodeRange.cloneRange();
22839 nodeEndRange.collapse(false);
22841 return rangeStartRange.compareBoundaryPoints(
22842 Range.START_TO_START, nodeEndRange) == -1 &&
22843 rangeEndRange.compareBoundaryPoints(
22844 Range.START_TO_START, nodeStartRange) == 1;
22848 rangeCompareNode : function(range, node)
22850 var nodeRange = node.ownerDocument.createRange();
22852 nodeRange.selectNode(node);
22854 nodeRange.selectNodeContents(node);
22858 range.collapse(true);
22860 nodeRange.collapse(true);
22862 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22863 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22865 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22867 var nodeIsBefore = ss == 1;
22868 var nodeIsAfter = ee == -1;
22870 if (nodeIsBefore && nodeIsAfter) {
22873 if (!nodeIsBefore && nodeIsAfter) {
22874 return 1; //right trailed.
22877 if (nodeIsBefore && !nodeIsAfter) {
22878 return 2; // left trailed.
22884 // private? - in a new class?
22885 cleanUpPaste : function()
22887 // cleans up the whole document..
22888 Roo.log('cleanuppaste');
22890 this.cleanUpChildren(this.doc.body);
22891 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22892 if (clean != this.doc.body.innerHTML) {
22893 this.doc.body.innerHTML = clean;
22898 cleanWordChars : function(input) {// change the chars to hex code
22899 var he = Roo.HtmlEditorCore;
22901 var output = input;
22902 Roo.each(he.swapCodes, function(sw) {
22903 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22905 output = output.replace(swapper, sw[1]);
22912 cleanUpChildren : function (n)
22914 if (!n.childNodes.length) {
22917 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22918 this.cleanUpChild(n.childNodes[i]);
22925 cleanUpChild : function (node)
22928 //console.log(node);
22929 if (node.nodeName == "#text") {
22930 // clean up silly Windows -- stuff?
22933 if (node.nodeName == "#comment") {
22934 node.parentNode.removeChild(node);
22935 // clean up silly Windows -- stuff?
22938 var lcname = node.tagName.toLowerCase();
22939 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22940 // whitelist of tags..
22942 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22944 node.parentNode.removeChild(node);
22949 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22951 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22952 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22954 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22955 // remove_keep_children = true;
22958 if (remove_keep_children) {
22959 this.cleanUpChildren(node);
22960 // inserts everything just before this node...
22961 while (node.childNodes.length) {
22962 var cn = node.childNodes[0];
22963 node.removeChild(cn);
22964 node.parentNode.insertBefore(cn, node);
22966 node.parentNode.removeChild(node);
22970 if (!node.attributes || !node.attributes.length) {
22971 this.cleanUpChildren(node);
22975 function cleanAttr(n,v)
22978 if (v.match(/^\./) || v.match(/^\//)) {
22981 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22984 if (v.match(/^#/)) {
22987 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22988 node.removeAttribute(n);
22992 var cwhite = this.cwhite;
22993 var cblack = this.cblack;
22995 function cleanStyle(n,v)
22997 if (v.match(/expression/)) { //XSS?? should we even bother..
22998 node.removeAttribute(n);
23002 var parts = v.split(/;/);
23005 Roo.each(parts, function(p) {
23006 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23010 var l = p.split(':').shift().replace(/\s+/g,'');
23011 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23013 if ( cwhite.length && cblack.indexOf(l) > -1) {
23014 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23015 //node.removeAttribute(n);
23019 // only allow 'c whitelisted system attributes'
23020 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23021 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23022 //node.removeAttribute(n);
23032 if (clean.length) {
23033 node.setAttribute(n, clean.join(';'));
23035 node.removeAttribute(n);
23041 for (var i = node.attributes.length-1; i > -1 ; i--) {
23042 var a = node.attributes[i];
23045 if (a.name.toLowerCase().substr(0,2)=='on') {
23046 node.removeAttribute(a.name);
23049 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23050 node.removeAttribute(a.name);
23053 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23054 cleanAttr(a.name,a.value); // fixme..
23057 if (a.name == 'style') {
23058 cleanStyle(a.name,a.value);
23061 /// clean up MS crap..
23062 // tecnically this should be a list of valid class'es..
23065 if (a.name == 'class') {
23066 if (a.value.match(/^Mso/)) {
23067 node.className = '';
23070 if (a.value.match(/^body$/)) {
23071 node.className = '';
23082 this.cleanUpChildren(node);
23088 * Clean up MS wordisms...
23090 cleanWord : function(node)
23095 this.cleanWord(this.doc.body);
23098 if (node.nodeName == "#text") {
23099 // clean up silly Windows -- stuff?
23102 if (node.nodeName == "#comment") {
23103 node.parentNode.removeChild(node);
23104 // clean up silly Windows -- stuff?
23108 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23109 node.parentNode.removeChild(node);
23113 // remove - but keep children..
23114 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23115 while (node.childNodes.length) {
23116 var cn = node.childNodes[0];
23117 node.removeChild(cn);
23118 node.parentNode.insertBefore(cn, node);
23120 node.parentNode.removeChild(node);
23121 this.iterateChildren(node, this.cleanWord);
23125 if (node.className.length) {
23127 var cn = node.className.split(/\W+/);
23129 Roo.each(cn, function(cls) {
23130 if (cls.match(/Mso[a-zA-Z]+/)) {
23135 node.className = cna.length ? cna.join(' ') : '';
23137 node.removeAttribute("class");
23141 if (node.hasAttribute("lang")) {
23142 node.removeAttribute("lang");
23145 if (node.hasAttribute("style")) {
23147 var styles = node.getAttribute("style").split(";");
23149 Roo.each(styles, function(s) {
23150 if (!s.match(/:/)) {
23153 var kv = s.split(":");
23154 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23157 // what ever is left... we allow.
23160 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23161 if (!nstyle.length) {
23162 node.removeAttribute('style');
23165 this.iterateChildren(node, this.cleanWord);
23171 * iterateChildren of a Node, calling fn each time, using this as the scole..
23172 * @param {DomNode} node node to iterate children of.
23173 * @param {Function} fn method of this class to call on each item.
23175 iterateChildren : function(node, fn)
23177 if (!node.childNodes.length) {
23180 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23181 fn.call(this, node.childNodes[i])
23187 * cleanTableWidths.
23189 * Quite often pasting from word etc.. results in tables with column and widths.
23190 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23193 cleanTableWidths : function(node)
23198 this.cleanTableWidths(this.doc.body);
23203 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23206 Roo.log(node.tagName);
23207 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23208 this.iterateChildren(node, this.cleanTableWidths);
23211 if (node.hasAttribute('width')) {
23212 node.removeAttribute('width');
23216 if (node.hasAttribute("style")) {
23219 var styles = node.getAttribute("style").split(";");
23221 Roo.each(styles, function(s) {
23222 if (!s.match(/:/)) {
23225 var kv = s.split(":");
23226 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23229 // what ever is left... we allow.
23232 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23233 if (!nstyle.length) {
23234 node.removeAttribute('style');
23238 this.iterateChildren(node, this.cleanTableWidths);
23246 domToHTML : function(currentElement, depth, nopadtext) {
23248 depth = depth || 0;
23249 nopadtext = nopadtext || false;
23251 if (!currentElement) {
23252 return this.domToHTML(this.doc.body);
23255 //Roo.log(currentElement);
23257 var allText = false;
23258 var nodeName = currentElement.nodeName;
23259 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23261 if (nodeName == '#text') {
23263 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23268 if (nodeName != 'BODY') {
23271 // Prints the node tagName, such as <A>, <IMG>, etc
23274 for(i = 0; i < currentElement.attributes.length;i++) {
23276 var aname = currentElement.attributes.item(i).name;
23277 if (!currentElement.attributes.item(i).value.length) {
23280 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23283 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23292 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23295 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23300 // Traverse the tree
23302 var currentElementChild = currentElement.childNodes.item(i);
23303 var allText = true;
23304 var innerHTML = '';
23306 while (currentElementChild) {
23307 // Formatting code (indent the tree so it looks nice on the screen)
23308 var nopad = nopadtext;
23309 if (lastnode == 'SPAN') {
23313 if (currentElementChild.nodeName == '#text') {
23314 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23315 toadd = nopadtext ? toadd : toadd.trim();
23316 if (!nopad && toadd.length > 80) {
23317 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23319 innerHTML += toadd;
23322 currentElementChild = currentElement.childNodes.item(i);
23328 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23330 // Recursively traverse the tree structure of the child node
23331 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23332 lastnode = currentElementChild.nodeName;
23334 currentElementChild=currentElement.childNodes.item(i);
23340 // The remaining code is mostly for formatting the tree
23341 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23346 ret+= "</"+tagName+">";
23352 applyBlacklists : function()
23354 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23355 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23359 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23360 if (b.indexOf(tag) > -1) {
23363 this.white.push(tag);
23367 Roo.each(w, function(tag) {
23368 if (b.indexOf(tag) > -1) {
23371 if (this.white.indexOf(tag) > -1) {
23374 this.white.push(tag);
23379 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23380 if (w.indexOf(tag) > -1) {
23383 this.black.push(tag);
23387 Roo.each(b, function(tag) {
23388 if (w.indexOf(tag) > -1) {
23391 if (this.black.indexOf(tag) > -1) {
23394 this.black.push(tag);
23399 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23400 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23404 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23405 if (b.indexOf(tag) > -1) {
23408 this.cwhite.push(tag);
23412 Roo.each(w, function(tag) {
23413 if (b.indexOf(tag) > -1) {
23416 if (this.cwhite.indexOf(tag) > -1) {
23419 this.cwhite.push(tag);
23424 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23425 if (w.indexOf(tag) > -1) {
23428 this.cblack.push(tag);
23432 Roo.each(b, function(tag) {
23433 if (w.indexOf(tag) > -1) {
23436 if (this.cblack.indexOf(tag) > -1) {
23439 this.cblack.push(tag);
23444 setStylesheets : function(stylesheets)
23446 if(typeof(stylesheets) == 'string'){
23447 Roo.get(this.iframe.contentDocument.head).createChild({
23449 rel : 'stylesheet',
23458 Roo.each(stylesheets, function(s) {
23463 Roo.get(_this.iframe.contentDocument.head).createChild({
23465 rel : 'stylesheet',
23474 removeStylesheets : function()
23478 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23483 setStyle : function(style)
23485 Roo.get(this.iframe.contentDocument.head).createChild({
23494 // hide stuff that is not compatible
23508 * @event specialkey
23512 * @cfg {String} fieldClass @hide
23515 * @cfg {String} focusClass @hide
23518 * @cfg {String} autoCreate @hide
23521 * @cfg {String} inputType @hide
23524 * @cfg {String} invalidClass @hide
23527 * @cfg {String} invalidText @hide
23530 * @cfg {String} msgFx @hide
23533 * @cfg {String} validateOnBlur @hide
23537 Roo.HtmlEditorCore.white = [
23538 'area', 'br', 'img', 'input', 'hr', 'wbr',
23540 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23541 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23542 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23543 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23544 'table', 'ul', 'xmp',
23546 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23549 'dir', 'menu', 'ol', 'ul', 'dl',
23555 Roo.HtmlEditorCore.black = [
23556 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23558 'base', 'basefont', 'bgsound', 'blink', 'body',
23559 'frame', 'frameset', 'head', 'html', 'ilayer',
23560 'iframe', 'layer', 'link', 'meta', 'object',
23561 'script', 'style' ,'title', 'xml' // clean later..
23563 Roo.HtmlEditorCore.clean = [
23564 'script', 'style', 'title', 'xml'
23566 Roo.HtmlEditorCore.remove = [
23571 Roo.HtmlEditorCore.ablack = [
23575 Roo.HtmlEditorCore.aclean = [
23576 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23580 Roo.HtmlEditorCore.pwhite= [
23581 'http', 'https', 'mailto'
23584 // white listed style attributes.
23585 Roo.HtmlEditorCore.cwhite= [
23586 // 'text-align', /// default is to allow most things..
23592 // black listed style attributes.
23593 Roo.HtmlEditorCore.cblack= [
23594 // 'font-size' -- this can be set by the project
23598 Roo.HtmlEditorCore.swapCodes =[
23617 * @class Roo.bootstrap.HtmlEditor
23618 * @extends Roo.bootstrap.TextArea
23619 * Bootstrap HtmlEditor class
23622 * Create a new HtmlEditor
23623 * @param {Object} config The config object
23626 Roo.bootstrap.HtmlEditor = function(config){
23627 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23628 if (!this.toolbars) {
23629 this.toolbars = [];
23632 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23635 * @event initialize
23636 * Fires when the editor is fully initialized (including the iframe)
23637 * @param {HtmlEditor} this
23642 * Fires when the editor is first receives the focus. Any insertion must wait
23643 * until after this event.
23644 * @param {HtmlEditor} this
23648 * @event beforesync
23649 * Fires before the textarea is updated with content from the editor iframe. Return false
23650 * to cancel the sync.
23651 * @param {HtmlEditor} this
23652 * @param {String} html
23656 * @event beforepush
23657 * Fires before the iframe editor is updated with content from the textarea. Return false
23658 * to cancel the push.
23659 * @param {HtmlEditor} this
23660 * @param {String} html
23665 * Fires when the textarea is updated with content from the editor iframe.
23666 * @param {HtmlEditor} this
23667 * @param {String} html
23672 * Fires when the iframe editor is updated with content from the textarea.
23673 * @param {HtmlEditor} this
23674 * @param {String} html
23678 * @event editmodechange
23679 * Fires when the editor switches edit modes
23680 * @param {HtmlEditor} this
23681 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23683 editmodechange: true,
23685 * @event editorevent
23686 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23687 * @param {HtmlEditor} this
23691 * @event firstfocus
23692 * Fires when on first focus - needed by toolbars..
23693 * @param {HtmlEditor} this
23698 * Auto save the htmlEditor value as a file into Events
23699 * @param {HtmlEditor} this
23703 * @event savedpreview
23704 * preview the saved version of htmlEditor
23705 * @param {HtmlEditor} this
23712 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23716 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23721 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23726 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23731 * @cfg {Number} height (in pixels)
23735 * @cfg {Number} width (in pixels)
23740 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23743 stylesheets: false,
23748 // private properties
23749 validationEvent : false,
23751 initialized : false,
23754 onFocus : Roo.emptyFn,
23756 hideMode:'offsets',
23758 tbContainer : false,
23762 toolbarContainer :function() {
23763 return this.wrap.select('.x-html-editor-tb',true).first();
23767 * Protected method that will not generally be called directly. It
23768 * is called when the editor creates its toolbar. Override this method if you need to
23769 * add custom toolbar buttons.
23770 * @param {HtmlEditor} editor
23772 createToolbar : function(){
23773 Roo.log('renewing');
23774 Roo.log("create toolbars");
23776 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23777 this.toolbars[0].render(this.toolbarContainer());
23781 // if (!editor.toolbars || !editor.toolbars.length) {
23782 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23785 // for (var i =0 ; i < editor.toolbars.length;i++) {
23786 // editor.toolbars[i] = Roo.factory(
23787 // typeof(editor.toolbars[i]) == 'string' ?
23788 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23789 // Roo.bootstrap.HtmlEditor);
23790 // editor.toolbars[i].init(editor);
23796 onRender : function(ct, position)
23798 // Roo.log("Call onRender: " + this.xtype);
23800 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23802 this.wrap = this.inputEl().wrap({
23803 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23806 this.editorcore.onRender(ct, position);
23808 if (this.resizable) {
23809 this.resizeEl = new Roo.Resizable(this.wrap, {
23813 minHeight : this.height,
23814 height: this.height,
23815 handles : this.resizable,
23818 resize : function(r, w, h) {
23819 _t.onResize(w,h); // -something
23825 this.createToolbar(this);
23828 if(!this.width && this.resizable){
23829 this.setSize(this.wrap.getSize());
23831 if (this.resizeEl) {
23832 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23833 // should trigger onReize..
23839 onResize : function(w, h)
23841 Roo.log('resize: ' +w + ',' + h );
23842 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23846 if(this.inputEl() ){
23847 if(typeof w == 'number'){
23848 var aw = w - this.wrap.getFrameWidth('lr');
23849 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23852 if(typeof h == 'number'){
23853 var tbh = -11; // fixme it needs to tool bar size!
23854 for (var i =0; i < this.toolbars.length;i++) {
23855 // fixme - ask toolbars for heights?
23856 tbh += this.toolbars[i].el.getHeight();
23857 //if (this.toolbars[i].footer) {
23858 // tbh += this.toolbars[i].footer.el.getHeight();
23866 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23867 ah -= 5; // knock a few pixes off for look..
23868 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23872 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23873 this.editorcore.onResize(ew,eh);
23878 * Toggles the editor between standard and source edit mode.
23879 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23881 toggleSourceEdit : function(sourceEditMode)
23883 this.editorcore.toggleSourceEdit(sourceEditMode);
23885 if(this.editorcore.sourceEditMode){
23886 Roo.log('editor - showing textarea');
23889 // Roo.log(this.syncValue());
23891 this.inputEl().removeClass(['hide', 'x-hidden']);
23892 this.inputEl().dom.removeAttribute('tabIndex');
23893 this.inputEl().focus();
23895 Roo.log('editor - hiding textarea');
23897 // Roo.log(this.pushValue());
23900 this.inputEl().addClass(['hide', 'x-hidden']);
23901 this.inputEl().dom.setAttribute('tabIndex', -1);
23902 //this.deferFocus();
23905 if(this.resizable){
23906 this.setSize(this.wrap.getSize());
23909 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23912 // private (for BoxComponent)
23913 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23915 // private (for BoxComponent)
23916 getResizeEl : function(){
23920 // private (for BoxComponent)
23921 getPositionEl : function(){
23926 initEvents : function(){
23927 this.originalValue = this.getValue();
23931 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23934 // markInvalid : Roo.emptyFn,
23936 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23939 // clearInvalid : Roo.emptyFn,
23941 setValue : function(v){
23942 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23943 this.editorcore.pushValue();
23948 deferFocus : function(){
23949 this.focus.defer(10, this);
23953 focus : function(){
23954 this.editorcore.focus();
23960 onDestroy : function(){
23966 for (var i =0; i < this.toolbars.length;i++) {
23967 // fixme - ask toolbars for heights?
23968 this.toolbars[i].onDestroy();
23971 this.wrap.dom.innerHTML = '';
23972 this.wrap.remove();
23977 onFirstFocus : function(){
23978 //Roo.log("onFirstFocus");
23979 this.editorcore.onFirstFocus();
23980 for (var i =0; i < this.toolbars.length;i++) {
23981 this.toolbars[i].onFirstFocus();
23987 syncValue : function()
23989 this.editorcore.syncValue();
23992 pushValue : function()
23994 this.editorcore.pushValue();
23998 // hide stuff that is not compatible
24012 * @event specialkey
24016 * @cfg {String} fieldClass @hide
24019 * @cfg {String} focusClass @hide
24022 * @cfg {String} autoCreate @hide
24025 * @cfg {String} inputType @hide
24029 * @cfg {String} invalidText @hide
24032 * @cfg {String} msgFx @hide
24035 * @cfg {String} validateOnBlur @hide
24044 Roo.namespace('Roo.bootstrap.htmleditor');
24046 * @class Roo.bootstrap.HtmlEditorToolbar1
24051 new Roo.bootstrap.HtmlEditor({
24054 new Roo.bootstrap.HtmlEditorToolbar1({
24055 disable : { fonts: 1 , format: 1, ..., ... , ...],
24061 * @cfg {Object} disable List of elements to disable..
24062 * @cfg {Array} btns List of additional buttons.
24066 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24069 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24072 Roo.apply(this, config);
24074 // default disabled, based on 'good practice'..
24075 this.disable = this.disable || {};
24076 Roo.applyIf(this.disable, {
24079 specialElements : true
24081 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24083 this.editor = config.editor;
24084 this.editorcore = config.editor.editorcore;
24086 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24088 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24089 // dont call parent... till later.
24091 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24096 editorcore : false,
24101 "h1","h2","h3","h4","h5","h6",
24103 "abbr", "acronym", "address", "cite", "samp", "var",
24107 onRender : function(ct, position)
24109 // Roo.log("Call onRender: " + this.xtype);
24111 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24113 this.el.dom.style.marginBottom = '0';
24115 var editorcore = this.editorcore;
24116 var editor= this.editor;
24119 var btn = function(id,cmd , toggle, handler, html){
24121 var event = toggle ? 'toggle' : 'click';
24126 xns: Roo.bootstrap,
24130 enableToggle:toggle !== false,
24132 pressed : toggle ? false : null,
24135 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24136 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24142 // var cb_box = function...
24147 xns: Roo.bootstrap,
24152 xns: Roo.bootstrap,
24156 Roo.each(this.formats, function(f) {
24157 style.menu.items.push({
24159 xns: Roo.bootstrap,
24160 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24165 editorcore.insertTag(this.tagname);
24172 children.push(style);
24174 btn('bold',false,true);
24175 btn('italic',false,true);
24176 btn('align-left', 'justifyleft',true);
24177 btn('align-center', 'justifycenter',true);
24178 btn('align-right' , 'justifyright',true);
24179 btn('link', false, false, function(btn) {
24180 //Roo.log("create link?");
24181 var url = prompt(this.createLinkText, this.defaultLinkValue);
24182 if(url && url != 'http:/'+'/'){
24183 this.editorcore.relayCmd('createlink', url);
24186 btn('list','insertunorderedlist',true);
24187 btn('pencil', false,true, function(btn){
24189 this.toggleSourceEdit(btn.pressed);
24192 if (this.editor.btns.length > 0) {
24193 for (var i = 0; i<this.editor.btns.length; i++) {
24194 children.push(this.editor.btns[i]);
24202 xns: Roo.bootstrap,
24207 xns: Roo.bootstrap,
24212 cog.menu.items.push({
24214 xns: Roo.bootstrap,
24215 html : Clean styles,
24220 editorcore.insertTag(this.tagname);
24229 this.xtype = 'NavSimplebar';
24231 for(var i=0;i< children.length;i++) {
24233 this.buttons.add(this.addxtypeChild(children[i]));
24237 editor.on('editorevent', this.updateToolbar, this);
24239 onBtnClick : function(id)
24241 this.editorcore.relayCmd(id);
24242 this.editorcore.focus();
24246 * Protected method that will not generally be called directly. It triggers
24247 * a toolbar update by reading the markup state of the current selection in the editor.
24249 updateToolbar: function(){
24251 if(!this.editorcore.activated){
24252 this.editor.onFirstFocus(); // is this neeed?
24256 var btns = this.buttons;
24257 var doc = this.editorcore.doc;
24258 btns.get('bold').setActive(doc.queryCommandState('bold'));
24259 btns.get('italic').setActive(doc.queryCommandState('italic'));
24260 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24262 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24263 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24264 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24266 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24267 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24270 var ans = this.editorcore.getAllAncestors();
24271 if (this.formatCombo) {
24274 var store = this.formatCombo.store;
24275 this.formatCombo.setValue("");
24276 for (var i =0; i < ans.length;i++) {
24277 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24279 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24287 // hides menus... - so this cant be on a menu...
24288 Roo.bootstrap.MenuMgr.hideAll();
24290 Roo.bootstrap.MenuMgr.hideAll();
24291 //this.editorsyncValue();
24293 onFirstFocus: function() {
24294 this.buttons.each(function(item){
24298 toggleSourceEdit : function(sourceEditMode){
24301 if(sourceEditMode){
24302 Roo.log("disabling buttons");
24303 this.buttons.each( function(item){
24304 if(item.cmd != 'pencil'){
24310 Roo.log("enabling buttons");
24311 if(this.editorcore.initialized){
24312 this.buttons.each( function(item){
24318 Roo.log("calling toggole on editor");
24319 // tell the editor that it's been pressed..
24320 this.editor.toggleSourceEdit(sourceEditMode);
24330 * @class Roo.bootstrap.Table.AbstractSelectionModel
24331 * @extends Roo.util.Observable
24332 * Abstract base class for grid SelectionModels. It provides the interface that should be
24333 * implemented by descendant classes. This class should not be directly instantiated.
24336 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24337 this.locked = false;
24338 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24342 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24343 /** @ignore Called by the grid automatically. Do not call directly. */
24344 init : function(grid){
24350 * Locks the selections.
24353 this.locked = true;
24357 * Unlocks the selections.
24359 unlock : function(){
24360 this.locked = false;
24364 * Returns true if the selections are locked.
24365 * @return {Boolean}
24367 isLocked : function(){
24368 return this.locked;
24372 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24373 * @class Roo.bootstrap.Table.RowSelectionModel
24374 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24375 * It supports multiple selections and keyboard selection/navigation.
24377 * @param {Object} config
24380 Roo.bootstrap.Table.RowSelectionModel = function(config){
24381 Roo.apply(this, config);
24382 this.selections = new Roo.util.MixedCollection(false, function(o){
24387 this.lastActive = false;
24391 * @event selectionchange
24392 * Fires when the selection changes
24393 * @param {SelectionModel} this
24395 "selectionchange" : true,
24397 * @event afterselectionchange
24398 * Fires after the selection changes (eg. by key press or clicking)
24399 * @param {SelectionModel} this
24401 "afterselectionchange" : true,
24403 * @event beforerowselect
24404 * Fires when a row is selected being selected, return false to cancel.
24405 * @param {SelectionModel} this
24406 * @param {Number} rowIndex The selected index
24407 * @param {Boolean} keepExisting False if other selections will be cleared
24409 "beforerowselect" : true,
24412 * Fires when a row is selected.
24413 * @param {SelectionModel} this
24414 * @param {Number} rowIndex The selected index
24415 * @param {Roo.data.Record} r The record
24417 "rowselect" : true,
24419 * @event rowdeselect
24420 * Fires when a row is deselected.
24421 * @param {SelectionModel} this
24422 * @param {Number} rowIndex The selected index
24424 "rowdeselect" : true
24426 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24427 this.locked = false;
24430 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24432 * @cfg {Boolean} singleSelect
24433 * True to allow selection of only one row at a time (defaults to false)
24435 singleSelect : false,
24438 initEvents : function()
24441 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24442 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24443 //}else{ // allow click to work like normal
24444 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24446 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24447 this.grid.on("rowclick", this.handleMouseDown, this);
24449 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24450 "up" : function(e){
24452 this.selectPrevious(e.shiftKey);
24453 }else if(this.last !== false && this.lastActive !== false){
24454 var last = this.last;
24455 this.selectRange(this.last, this.lastActive-1);
24456 this.grid.getView().focusRow(this.lastActive);
24457 if(last !== false){
24461 this.selectFirstRow();
24463 this.fireEvent("afterselectionchange", this);
24465 "down" : function(e){
24467 this.selectNext(e.shiftKey);
24468 }else if(this.last !== false && this.lastActive !== false){
24469 var last = this.last;
24470 this.selectRange(this.last, this.lastActive+1);
24471 this.grid.getView().focusRow(this.lastActive);
24472 if(last !== false){
24476 this.selectFirstRow();
24478 this.fireEvent("afterselectionchange", this);
24482 this.grid.store.on('load', function(){
24483 this.selections.clear();
24486 var view = this.grid.view;
24487 view.on("refresh", this.onRefresh, this);
24488 view.on("rowupdated", this.onRowUpdated, this);
24489 view.on("rowremoved", this.onRemove, this);
24494 onRefresh : function()
24496 var ds = this.grid.store, i, v = this.grid.view;
24497 var s = this.selections;
24498 s.each(function(r){
24499 if((i = ds.indexOfId(r.id)) != -1){
24508 onRemove : function(v, index, r){
24509 this.selections.remove(r);
24513 onRowUpdated : function(v, index, r){
24514 if(this.isSelected(r)){
24515 v.onRowSelect(index);
24521 * @param {Array} records The records to select
24522 * @param {Boolean} keepExisting (optional) True to keep existing selections
24524 selectRecords : function(records, keepExisting)
24527 this.clearSelections();
24529 var ds = this.grid.store;
24530 for(var i = 0, len = records.length; i < len; i++){
24531 this.selectRow(ds.indexOf(records[i]), true);
24536 * Gets the number of selected rows.
24539 getCount : function(){
24540 return this.selections.length;
24544 * Selects the first row in the grid.
24546 selectFirstRow : function(){
24551 * Select the last row.
24552 * @param {Boolean} keepExisting (optional) True to keep existing selections
24554 selectLastRow : function(keepExisting){
24555 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24556 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24560 * Selects the row immediately following the last selected row.
24561 * @param {Boolean} keepExisting (optional) True to keep existing selections
24563 selectNext : function(keepExisting)
24565 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24566 this.selectRow(this.last+1, keepExisting);
24567 this.grid.getView().focusRow(this.last);
24572 * Selects the row that precedes the last selected row.
24573 * @param {Boolean} keepExisting (optional) True to keep existing selections
24575 selectPrevious : function(keepExisting){
24577 this.selectRow(this.last-1, keepExisting);
24578 this.grid.getView().focusRow(this.last);
24583 * Returns the selected records
24584 * @return {Array} Array of selected records
24586 getSelections : function(){
24587 return [].concat(this.selections.items);
24591 * Returns the first selected record.
24594 getSelected : function(){
24595 return this.selections.itemAt(0);
24600 * Clears all selections.
24602 clearSelections : function(fast)
24608 var ds = this.grid.store;
24609 var s = this.selections;
24610 s.each(function(r){
24611 this.deselectRow(ds.indexOfId(r.id));
24615 this.selections.clear();
24622 * Selects all rows.
24624 selectAll : function(){
24628 this.selections.clear();
24629 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24630 this.selectRow(i, true);
24635 * Returns True if there is a selection.
24636 * @return {Boolean}
24638 hasSelection : function(){
24639 return this.selections.length > 0;
24643 * Returns True if the specified row is selected.
24644 * @param {Number/Record} record The record or index of the record to check
24645 * @return {Boolean}
24647 isSelected : function(index){
24648 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24649 return (r && this.selections.key(r.id) ? true : false);
24653 * Returns True if the specified record id is selected.
24654 * @param {String} id The id of record to check
24655 * @return {Boolean}
24657 isIdSelected : function(id){
24658 return (this.selections.key(id) ? true : false);
24663 handleMouseDBClick : function(e, t){
24667 handleMouseDown : function(e, t)
24669 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24670 if(this.isLocked() || rowIndex < 0 ){
24673 if(e.shiftKey && this.last !== false){
24674 var last = this.last;
24675 this.selectRange(last, rowIndex, e.ctrlKey);
24676 this.last = last; // reset the last
24680 var isSelected = this.isSelected(rowIndex);
24681 //Roo.log("select row:" + rowIndex);
24683 this.deselectRow(rowIndex);
24685 this.selectRow(rowIndex, true);
24689 if(e.button !== 0 && isSelected){
24690 alert('rowIndex 2: ' + rowIndex);
24691 view.focusRow(rowIndex);
24692 }else if(e.ctrlKey && isSelected){
24693 this.deselectRow(rowIndex);
24694 }else if(!isSelected){
24695 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24696 view.focusRow(rowIndex);
24700 this.fireEvent("afterselectionchange", this);
24703 handleDragableRowClick : function(grid, rowIndex, e)
24705 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24706 this.selectRow(rowIndex, false);
24707 grid.view.focusRow(rowIndex);
24708 this.fireEvent("afterselectionchange", this);
24713 * Selects multiple rows.
24714 * @param {Array} rows Array of the indexes of the row to select
24715 * @param {Boolean} keepExisting (optional) True to keep existing selections
24717 selectRows : function(rows, keepExisting){
24719 this.clearSelections();
24721 for(var i = 0, len = rows.length; i < len; i++){
24722 this.selectRow(rows[i], true);
24727 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24728 * @param {Number} startRow The index of the first row in the range
24729 * @param {Number} endRow The index of the last row in the range
24730 * @param {Boolean} keepExisting (optional) True to retain existing selections
24732 selectRange : function(startRow, endRow, keepExisting){
24737 this.clearSelections();
24739 if(startRow <= endRow){
24740 for(var i = startRow; i <= endRow; i++){
24741 this.selectRow(i, true);
24744 for(var i = startRow; i >= endRow; i--){
24745 this.selectRow(i, true);
24751 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24752 * @param {Number} startRow The index of the first row in the range
24753 * @param {Number} endRow The index of the last row in the range
24755 deselectRange : function(startRow, endRow, preventViewNotify){
24759 for(var i = startRow; i <= endRow; i++){
24760 this.deselectRow(i, preventViewNotify);
24766 * @param {Number} row The index of the row to select
24767 * @param {Boolean} keepExisting (optional) True to keep existing selections
24769 selectRow : function(index, keepExisting, preventViewNotify)
24771 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24774 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24775 if(!keepExisting || this.singleSelect){
24776 this.clearSelections();
24779 var r = this.grid.store.getAt(index);
24780 //console.log('selectRow - record id :' + r.id);
24782 this.selections.add(r);
24783 this.last = this.lastActive = index;
24784 if(!preventViewNotify){
24785 var proxy = new Roo.Element(
24786 this.grid.getRowDom(index)
24788 proxy.addClass('bg-info info');
24790 this.fireEvent("rowselect", this, index, r);
24791 this.fireEvent("selectionchange", this);
24797 * @param {Number} row The index of the row to deselect
24799 deselectRow : function(index, preventViewNotify)
24804 if(this.last == index){
24807 if(this.lastActive == index){
24808 this.lastActive = false;
24811 var r = this.grid.store.getAt(index);
24816 this.selections.remove(r);
24817 //.console.log('deselectRow - record id :' + r.id);
24818 if(!preventViewNotify){
24820 var proxy = new Roo.Element(
24821 this.grid.getRowDom(index)
24823 proxy.removeClass('bg-info info');
24825 this.fireEvent("rowdeselect", this, index);
24826 this.fireEvent("selectionchange", this);
24830 restoreLast : function(){
24832 this.last = this._last;
24837 acceptsNav : function(row, col, cm){
24838 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24842 onEditorKey : function(field, e){
24843 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24848 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24850 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24852 }else if(k == e.ENTER && !e.ctrlKey){
24856 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24858 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24860 }else if(k == e.ESC){
24864 g.startEditing(newCell[0], newCell[1]);
24870 * Ext JS Library 1.1.1
24871 * Copyright(c) 2006-2007, Ext JS, LLC.
24873 * Originally Released Under LGPL - original licence link has changed is not relivant.
24876 * <script type="text/javascript">
24880 * @class Roo.bootstrap.PagingToolbar
24881 * @extends Roo.bootstrap.NavSimplebar
24882 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24884 * Create a new PagingToolbar
24885 * @param {Object} config The config object
24886 * @param {Roo.data.Store} store
24888 Roo.bootstrap.PagingToolbar = function(config)
24890 // old args format still supported... - xtype is prefered..
24891 // created from xtype...
24893 this.ds = config.dataSource;
24895 if (config.store && !this.ds) {
24896 this.store= Roo.factory(config.store, Roo.data);
24897 this.ds = this.store;
24898 this.ds.xmodule = this.xmodule || false;
24901 this.toolbarItems = [];
24902 if (config.items) {
24903 this.toolbarItems = config.items;
24906 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24911 this.bind(this.ds);
24914 if (Roo.bootstrap.version == 4) {
24915 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24917 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24922 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24924 * @cfg {Roo.data.Store} dataSource
24925 * The underlying data store providing the paged data
24928 * @cfg {String/HTMLElement/Element} container
24929 * container The id or element that will contain the toolbar
24932 * @cfg {Boolean} displayInfo
24933 * True to display the displayMsg (defaults to false)
24936 * @cfg {Number} pageSize
24937 * The number of records to display per page (defaults to 20)
24941 * @cfg {String} displayMsg
24942 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24944 displayMsg : 'Displaying {0} - {1} of {2}',
24946 * @cfg {String} emptyMsg
24947 * The message to display when no records are found (defaults to "No data to display")
24949 emptyMsg : 'No data to display',
24951 * Customizable piece of the default paging text (defaults to "Page")
24954 beforePageText : "Page",
24956 * Customizable piece of the default paging text (defaults to "of %0")
24959 afterPageText : "of {0}",
24961 * Customizable piece of the default paging text (defaults to "First Page")
24964 firstText : "First Page",
24966 * Customizable piece of the default paging text (defaults to "Previous Page")
24969 prevText : "Previous Page",
24971 * Customizable piece of the default paging text (defaults to "Next Page")
24974 nextText : "Next Page",
24976 * Customizable piece of the default paging text (defaults to "Last Page")
24979 lastText : "Last Page",
24981 * Customizable piece of the default paging text (defaults to "Refresh")
24984 refreshText : "Refresh",
24988 onRender : function(ct, position)
24990 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24991 this.navgroup.parentId = this.id;
24992 this.navgroup.onRender(this.el, null);
24993 // add the buttons to the navgroup
24995 if(this.displayInfo){
24996 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24997 this.displayEl = this.el.select('.x-paging-info', true).first();
24998 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24999 // this.displayEl = navel.el.select('span',true).first();
25005 Roo.each(_this.buttons, function(e){ // this might need to use render????
25006 Roo.factory(e).render(_this.el);
25010 Roo.each(_this.toolbarItems, function(e) {
25011 _this.navgroup.addItem(e);
25015 this.first = this.navgroup.addItem({
25016 tooltip: this.firstText,
25017 cls: "prev btn-outline-secondary",
25018 html : ' <i class="fa fa-step-backward"></i>',
25020 preventDefault: true,
25021 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25024 this.prev = this.navgroup.addItem({
25025 tooltip: this.prevText,
25026 cls: "prev btn-outline-secondary",
25027 html : ' <i class="fa fa-backward"></i>',
25029 preventDefault: true,
25030 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25032 //this.addSeparator();
25035 var field = this.navgroup.addItem( {
25037 cls : 'x-paging-position btn-outline-secondary',
25039 html : this.beforePageText +
25040 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25041 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25044 this.field = field.el.select('input', true).first();
25045 this.field.on("keydown", this.onPagingKeydown, this);
25046 this.field.on("focus", function(){this.dom.select();});
25049 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25050 //this.field.setHeight(18);
25051 //this.addSeparator();
25052 this.next = this.navgroup.addItem({
25053 tooltip: this.nextText,
25054 cls: "next btn-outline-secondary",
25055 html : ' <i class="fa fa-forward"></i>',
25057 preventDefault: true,
25058 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25060 this.last = this.navgroup.addItem({
25061 tooltip: this.lastText,
25062 html : ' <i class="fa fa-step-forward"></i>',
25063 cls: "next btn-outline-secondary",
25065 preventDefault: true,
25066 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25068 //this.addSeparator();
25069 this.loading = this.navgroup.addItem({
25070 tooltip: this.refreshText,
25071 cls: "btn-outline-secondary",
25072 html : ' <i class="fa fa-refresh"></i>',
25073 preventDefault: true,
25074 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25080 updateInfo : function(){
25081 if(this.displayEl){
25082 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25083 var msg = count == 0 ?
25087 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25089 this.displayEl.update(msg);
25094 onLoad : function(ds, r, o)
25096 this.cursor = o.params.start ? o.params.start : 0;
25098 var d = this.getPageData(),
25103 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25104 this.field.dom.value = ap;
25105 this.first.setDisabled(ap == 1);
25106 this.prev.setDisabled(ap == 1);
25107 this.next.setDisabled(ap == ps);
25108 this.last.setDisabled(ap == ps);
25109 this.loading.enable();
25114 getPageData : function(){
25115 var total = this.ds.getTotalCount();
25118 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25119 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25124 onLoadError : function(){
25125 this.loading.enable();
25129 onPagingKeydown : function(e){
25130 var k = e.getKey();
25131 var d = this.getPageData();
25133 var v = this.field.dom.value, pageNum;
25134 if(!v || isNaN(pageNum = parseInt(v, 10))){
25135 this.field.dom.value = d.activePage;
25138 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25139 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25142 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))
25144 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25145 this.field.dom.value = pageNum;
25146 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25149 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25151 var v = this.field.dom.value, pageNum;
25152 var increment = (e.shiftKey) ? 10 : 1;
25153 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25156 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25157 this.field.dom.value = d.activePage;
25160 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25162 this.field.dom.value = parseInt(v, 10) + increment;
25163 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25164 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25171 beforeLoad : function(){
25173 this.loading.disable();
25178 onClick : function(which){
25187 ds.load({params:{start: 0, limit: this.pageSize}});
25190 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25193 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25196 var total = ds.getTotalCount();
25197 var extra = total % this.pageSize;
25198 var lastStart = extra ? (total - extra) : total-this.pageSize;
25199 ds.load({params:{start: lastStart, limit: this.pageSize}});
25202 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25208 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25209 * @param {Roo.data.Store} store The data store to unbind
25211 unbind : function(ds){
25212 ds.un("beforeload", this.beforeLoad, this);
25213 ds.un("load", this.onLoad, this);
25214 ds.un("loadexception", this.onLoadError, this);
25215 ds.un("remove", this.updateInfo, this);
25216 ds.un("add", this.updateInfo, this);
25217 this.ds = undefined;
25221 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25222 * @param {Roo.data.Store} store The data store to bind
25224 bind : function(ds){
25225 ds.on("beforeload", this.beforeLoad, this);
25226 ds.on("load", this.onLoad, this);
25227 ds.on("loadexception", this.onLoadError, this);
25228 ds.on("remove", this.updateInfo, this);
25229 ds.on("add", this.updateInfo, this);
25240 * @class Roo.bootstrap.MessageBar
25241 * @extends Roo.bootstrap.Component
25242 * Bootstrap MessageBar class
25243 * @cfg {String} html contents of the MessageBar
25244 * @cfg {String} weight (info | success | warning | danger) default info
25245 * @cfg {String} beforeClass insert the bar before the given class
25246 * @cfg {Boolean} closable (true | false) default false
25247 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25250 * Create a new Element
25251 * @param {Object} config The config object
25254 Roo.bootstrap.MessageBar = function(config){
25255 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25258 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25264 beforeClass: 'bootstrap-sticky-wrap',
25266 getAutoCreate : function(){
25270 cls: 'alert alert-dismissable alert-' + this.weight,
25275 html: this.html || ''
25281 cfg.cls += ' alert-messages-fixed';
25295 onRender : function(ct, position)
25297 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25300 var cfg = Roo.apply({}, this.getAutoCreate());
25304 cfg.cls += ' ' + this.cls;
25307 cfg.style = this.style;
25309 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25311 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25314 this.el.select('>button.close').on('click', this.hide, this);
25320 if (!this.rendered) {
25326 this.fireEvent('show', this);
25332 if (!this.rendered) {
25338 this.fireEvent('hide', this);
25341 update : function()
25343 // var e = this.el.dom.firstChild;
25345 // if(this.closable){
25346 // e = e.nextSibling;
25349 // e.data = this.html || '';
25351 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25367 * @class Roo.bootstrap.Graph
25368 * @extends Roo.bootstrap.Component
25369 * Bootstrap Graph class
25373 @cfg {String} graphtype bar | vbar | pie
25374 @cfg {number} g_x coodinator | centre x (pie)
25375 @cfg {number} g_y coodinator | centre y (pie)
25376 @cfg {number} g_r radius (pie)
25377 @cfg {number} g_height height of the chart (respected by all elements in the set)
25378 @cfg {number} g_width width of the chart (respected by all elements in the set)
25379 @cfg {Object} title The title of the chart
25382 -opts (object) options for the chart
25384 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25385 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25387 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.
25388 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25390 o stretch (boolean)
25392 -opts (object) options for the pie
25395 o startAngle (number)
25396 o endAngle (number)
25400 * Create a new Input
25401 * @param {Object} config The config object
25404 Roo.bootstrap.Graph = function(config){
25405 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25411 * The img click event for the img.
25412 * @param {Roo.EventObject} e
25418 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25429 //g_colors: this.colors,
25436 getAutoCreate : function(){
25447 onRender : function(ct,position){
25450 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25452 if (typeof(Raphael) == 'undefined') {
25453 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25457 this.raphael = Raphael(this.el.dom);
25459 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25460 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25461 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25462 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25464 r.text(160, 10, "Single Series Chart").attr(txtattr);
25465 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25466 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25467 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25469 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25470 r.barchart(330, 10, 300, 220, data1);
25471 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25472 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25475 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25476 // r.barchart(30, 30, 560, 250, xdata, {
25477 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25478 // axis : "0 0 1 1",
25479 // axisxlabels : xdata
25480 // //yvalues : cols,
25483 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25485 // this.load(null,xdata,{
25486 // axis : "0 0 1 1",
25487 // axisxlabels : xdata
25492 load : function(graphtype,xdata,opts)
25494 this.raphael.clear();
25496 graphtype = this.graphtype;
25501 var r = this.raphael,
25502 fin = function () {
25503 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25505 fout = function () {
25506 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25508 pfin = function() {
25509 this.sector.stop();
25510 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25513 this.label[0].stop();
25514 this.label[0].attr({ r: 7.5 });
25515 this.label[1].attr({ "font-weight": 800 });
25518 pfout = function() {
25519 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25522 this.label[0].animate({ r: 5 }, 500, "bounce");
25523 this.label[1].attr({ "font-weight": 400 });
25529 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25532 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25535 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25536 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25538 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25545 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25550 setTitle: function(o)
25555 initEvents: function() {
25558 this.el.on('click', this.onClick, this);
25562 onClick : function(e)
25564 Roo.log('img onclick');
25565 this.fireEvent('click', this, e);
25577 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25580 * @class Roo.bootstrap.dash.NumberBox
25581 * @extends Roo.bootstrap.Component
25582 * Bootstrap NumberBox class
25583 * @cfg {String} headline Box headline
25584 * @cfg {String} content Box content
25585 * @cfg {String} icon Box icon
25586 * @cfg {String} footer Footer text
25587 * @cfg {String} fhref Footer href
25590 * Create a new NumberBox
25591 * @param {Object} config The config object
25595 Roo.bootstrap.dash.NumberBox = function(config){
25596 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25600 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25609 getAutoCreate : function(){
25613 cls : 'small-box ',
25621 cls : 'roo-headline',
25622 html : this.headline
25626 cls : 'roo-content',
25627 html : this.content
25641 cls : 'ion ' + this.icon
25650 cls : 'small-box-footer',
25651 href : this.fhref || '#',
25655 cfg.cn.push(footer);
25662 onRender : function(ct,position){
25663 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25670 setHeadline: function (value)
25672 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25675 setFooter: function (value, href)
25677 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25680 this.el.select('a.small-box-footer',true).first().attr('href', href);
25685 setContent: function (value)
25687 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25690 initEvents: function()
25704 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25707 * @class Roo.bootstrap.dash.TabBox
25708 * @extends Roo.bootstrap.Component
25709 * Bootstrap TabBox class
25710 * @cfg {String} title Title of the TabBox
25711 * @cfg {String} icon Icon of the TabBox
25712 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25713 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25716 * Create a new TabBox
25717 * @param {Object} config The config object
25721 Roo.bootstrap.dash.TabBox = function(config){
25722 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25727 * When a pane is added
25728 * @param {Roo.bootstrap.dash.TabPane} pane
25732 * @event activatepane
25733 * When a pane is activated
25734 * @param {Roo.bootstrap.dash.TabPane} pane
25736 "activatepane" : true
25744 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25749 tabScrollable : false,
25751 getChildContainer : function()
25753 return this.el.select('.tab-content', true).first();
25756 getAutoCreate : function(){
25760 cls: 'pull-left header',
25768 cls: 'fa ' + this.icon
25774 cls: 'nav nav-tabs pull-right',
25780 if(this.tabScrollable){
25787 cls: 'nav nav-tabs pull-right',
25798 cls: 'nav-tabs-custom',
25803 cls: 'tab-content no-padding',
25811 initEvents : function()
25813 //Roo.log('add add pane handler');
25814 this.on('addpane', this.onAddPane, this);
25817 * Updates the box title
25818 * @param {String} html to set the title to.
25820 setTitle : function(value)
25822 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25824 onAddPane : function(pane)
25826 this.panes.push(pane);
25827 //Roo.log('addpane');
25829 // tabs are rendere left to right..
25830 if(!this.showtabs){
25834 var ctr = this.el.select('.nav-tabs', true).first();
25837 var existing = ctr.select('.nav-tab',true);
25838 var qty = existing.getCount();;
25841 var tab = ctr.createChild({
25843 cls : 'nav-tab' + (qty ? '' : ' active'),
25851 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25854 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25856 pane.el.addClass('active');
25861 onTabClick : function(ev,un,ob,pane)
25863 //Roo.log('tab - prev default');
25864 ev.preventDefault();
25867 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25868 pane.tab.addClass('active');
25869 //Roo.log(pane.title);
25870 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25871 // technically we should have a deactivate event.. but maybe add later.
25872 // and it should not de-activate the selected tab...
25873 this.fireEvent('activatepane', pane);
25874 pane.el.addClass('active');
25875 pane.fireEvent('activate');
25880 getActivePane : function()
25883 Roo.each(this.panes, function(p) {
25884 if(p.el.hasClass('active')){
25905 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25907 * @class Roo.bootstrap.TabPane
25908 * @extends Roo.bootstrap.Component
25909 * Bootstrap TabPane class
25910 * @cfg {Boolean} active (false | true) Default false
25911 * @cfg {String} title title of panel
25915 * Create a new TabPane
25916 * @param {Object} config The config object
25919 Roo.bootstrap.dash.TabPane = function(config){
25920 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25926 * When a pane is activated
25927 * @param {Roo.bootstrap.dash.TabPane} pane
25934 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25939 // the tabBox that this is attached to.
25942 getAutoCreate : function()
25950 cfg.cls += ' active';
25955 initEvents : function()
25957 //Roo.log('trigger add pane handler');
25958 this.parent().fireEvent('addpane', this)
25962 * Updates the tab title
25963 * @param {String} html to set the title to.
25965 setTitle: function(str)
25971 this.tab.select('a', true).first().dom.innerHTML = str;
25988 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25991 * @class Roo.bootstrap.menu.Menu
25992 * @extends Roo.bootstrap.Component
25993 * Bootstrap Menu class - container for Menu
25994 * @cfg {String} html Text of the menu
25995 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25996 * @cfg {String} icon Font awesome icon
25997 * @cfg {String} pos Menu align to (top | bottom) default bottom
26001 * Create a new Menu
26002 * @param {Object} config The config object
26006 Roo.bootstrap.menu.Menu = function(config){
26007 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26011 * @event beforeshow
26012 * Fires before this menu is displayed
26013 * @param {Roo.bootstrap.menu.Menu} this
26017 * @event beforehide
26018 * Fires before this menu is hidden
26019 * @param {Roo.bootstrap.menu.Menu} this
26024 * Fires after this menu is displayed
26025 * @param {Roo.bootstrap.menu.Menu} this
26030 * Fires after this menu is hidden
26031 * @param {Roo.bootstrap.menu.Menu} this
26036 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26037 * @param {Roo.bootstrap.menu.Menu} this
26038 * @param {Roo.EventObject} e
26045 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26049 weight : 'default',
26054 getChildContainer : function() {
26055 if(this.isSubMenu){
26059 return this.el.select('ul.dropdown-menu', true).first();
26062 getAutoCreate : function()
26067 cls : 'roo-menu-text',
26075 cls : 'fa ' + this.icon
26086 cls : 'dropdown-button btn btn-' + this.weight,
26091 cls : 'dropdown-toggle btn btn-' + this.weight,
26101 cls : 'dropdown-menu'
26107 if(this.pos == 'top'){
26108 cfg.cls += ' dropup';
26111 if(this.isSubMenu){
26114 cls : 'dropdown-menu'
26121 onRender : function(ct, position)
26123 this.isSubMenu = ct.hasClass('dropdown-submenu');
26125 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26128 initEvents : function()
26130 if(this.isSubMenu){
26134 this.hidden = true;
26136 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26137 this.triggerEl.on('click', this.onTriggerPress, this);
26139 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26140 this.buttonEl.on('click', this.onClick, this);
26146 if(this.isSubMenu){
26150 return this.el.select('ul.dropdown-menu', true).first();
26153 onClick : function(e)
26155 this.fireEvent("click", this, e);
26158 onTriggerPress : function(e)
26160 if (this.isVisible()) {
26167 isVisible : function(){
26168 return !this.hidden;
26173 this.fireEvent("beforeshow", this);
26175 this.hidden = false;
26176 this.el.addClass('open');
26178 Roo.get(document).on("mouseup", this.onMouseUp, this);
26180 this.fireEvent("show", this);
26187 this.fireEvent("beforehide", this);
26189 this.hidden = true;
26190 this.el.removeClass('open');
26192 Roo.get(document).un("mouseup", this.onMouseUp);
26194 this.fireEvent("hide", this);
26197 onMouseUp : function()
26211 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26214 * @class Roo.bootstrap.menu.Item
26215 * @extends Roo.bootstrap.Component
26216 * Bootstrap MenuItem class
26217 * @cfg {Boolean} submenu (true | false) default false
26218 * @cfg {String} html text of the item
26219 * @cfg {String} href the link
26220 * @cfg {Boolean} disable (true | false) default false
26221 * @cfg {Boolean} preventDefault (true | false) default true
26222 * @cfg {String} icon Font awesome icon
26223 * @cfg {String} pos Submenu align to (left | right) default right
26227 * Create a new Item
26228 * @param {Object} config The config object
26232 Roo.bootstrap.menu.Item = function(config){
26233 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26237 * Fires when the mouse is hovering over this menu
26238 * @param {Roo.bootstrap.menu.Item} this
26239 * @param {Roo.EventObject} e
26244 * Fires when the mouse exits this menu
26245 * @param {Roo.bootstrap.menu.Item} this
26246 * @param {Roo.EventObject} e
26252 * The raw click event for the entire grid.
26253 * @param {Roo.EventObject} e
26259 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26264 preventDefault: true,
26269 getAutoCreate : function()
26274 cls : 'roo-menu-item-text',
26282 cls : 'fa ' + this.icon
26291 href : this.href || '#',
26298 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26302 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26304 if(this.pos == 'left'){
26305 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26312 initEvents : function()
26314 this.el.on('mouseover', this.onMouseOver, this);
26315 this.el.on('mouseout', this.onMouseOut, this);
26317 this.el.select('a', true).first().on('click', this.onClick, this);
26321 onClick : function(e)
26323 if(this.preventDefault){
26324 e.preventDefault();
26327 this.fireEvent("click", this, e);
26330 onMouseOver : function(e)
26332 if(this.submenu && this.pos == 'left'){
26333 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26336 this.fireEvent("mouseover", this, e);
26339 onMouseOut : function(e)
26341 this.fireEvent("mouseout", this, e);
26353 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26356 * @class Roo.bootstrap.menu.Separator
26357 * @extends Roo.bootstrap.Component
26358 * Bootstrap Separator class
26361 * Create a new Separator
26362 * @param {Object} config The config object
26366 Roo.bootstrap.menu.Separator = function(config){
26367 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26370 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26372 getAutoCreate : function(){
26393 * @class Roo.bootstrap.Tooltip
26394 * Bootstrap Tooltip class
26395 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26396 * to determine which dom element triggers the tooltip.
26398 * It needs to add support for additional attributes like tooltip-position
26401 * Create a new Toolti
26402 * @param {Object} config The config object
26405 Roo.bootstrap.Tooltip = function(config){
26406 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26408 this.alignment = Roo.bootstrap.Tooltip.alignment;
26410 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26411 this.alignment = config.alignment;
26416 Roo.apply(Roo.bootstrap.Tooltip, {
26418 * @function init initialize tooltip monitoring.
26422 currentTip : false,
26423 currentRegion : false,
26429 Roo.get(document).on('mouseover', this.enter ,this);
26430 Roo.get(document).on('mouseout', this.leave, this);
26433 this.currentTip = new Roo.bootstrap.Tooltip();
26436 enter : function(ev)
26438 var dom = ev.getTarget();
26440 //Roo.log(['enter',dom]);
26441 var el = Roo.fly(dom);
26442 if (this.currentEl) {
26444 //Roo.log(this.currentEl);
26445 //Roo.log(this.currentEl.contains(dom));
26446 if (this.currentEl == el) {
26449 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26455 if (this.currentTip.el) {
26456 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26460 if(!el || el.dom == document){
26466 // you can not look for children, as if el is the body.. then everythign is the child..
26467 if (!el.attr('tooltip')) { //
26468 if (!el.select("[tooltip]").elements.length) {
26471 // is the mouse over this child...?
26472 bindEl = el.select("[tooltip]").first();
26473 var xy = ev.getXY();
26474 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26475 //Roo.log("not in region.");
26478 //Roo.log("child element over..");
26481 this.currentEl = bindEl;
26482 this.currentTip.bind(bindEl);
26483 this.currentRegion = Roo.lib.Region.getRegion(dom);
26484 this.currentTip.enter();
26487 leave : function(ev)
26489 var dom = ev.getTarget();
26490 //Roo.log(['leave',dom]);
26491 if (!this.currentEl) {
26496 if (dom != this.currentEl.dom) {
26499 var xy = ev.getXY();
26500 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26503 // only activate leave if mouse cursor is outside... bounding box..
26508 if (this.currentTip) {
26509 this.currentTip.leave();
26511 //Roo.log('clear currentEl');
26512 this.currentEl = false;
26517 'left' : ['r-l', [-2,0], 'right'],
26518 'right' : ['l-r', [2,0], 'left'],
26519 'bottom' : ['t-b', [0,2], 'top'],
26520 'top' : [ 'b-t', [0,-2], 'bottom']
26526 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26531 delay : null, // can be { show : 300 , hide: 500}
26535 hoverState : null, //???
26537 placement : 'bottom',
26541 getAutoCreate : function(){
26548 cls : 'tooltip-arrow'
26551 cls : 'tooltip-inner'
26558 bind : function(el)
26564 enter : function () {
26566 if (this.timeout != null) {
26567 clearTimeout(this.timeout);
26570 this.hoverState = 'in';
26571 //Roo.log("enter - show");
26572 if (!this.delay || !this.delay.show) {
26577 this.timeout = setTimeout(function () {
26578 if (_t.hoverState == 'in') {
26581 }, this.delay.show);
26585 clearTimeout(this.timeout);
26587 this.hoverState = 'out';
26588 if (!this.delay || !this.delay.hide) {
26594 this.timeout = setTimeout(function () {
26595 //Roo.log("leave - timeout");
26597 if (_t.hoverState == 'out') {
26599 Roo.bootstrap.Tooltip.currentEl = false;
26604 show : function (msg)
26607 this.render(document.body);
26610 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26612 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26614 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26616 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26618 var placement = typeof this.placement == 'function' ?
26619 this.placement.call(this, this.el, on_el) :
26622 var autoToken = /\s?auto?\s?/i;
26623 var autoPlace = autoToken.test(placement);
26625 placement = placement.replace(autoToken, '') || 'top';
26629 //this.el.setXY([0,0]);
26631 //this.el.dom.style.display='block';
26633 //this.el.appendTo(on_el);
26635 var p = this.getPosition();
26636 var box = this.el.getBox();
26642 var align = this.alignment[placement];
26644 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26646 if(placement == 'top' || placement == 'bottom'){
26648 placement = 'right';
26651 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26652 placement = 'left';
26655 var scroll = Roo.select('body', true).first().getScroll();
26657 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26661 align = this.alignment[placement];
26664 this.el.alignTo(this.bindEl, align[0],align[1]);
26665 //var arrow = this.el.select('.arrow',true).first();
26666 //arrow.set(align[2],
26668 this.el.addClass(placement);
26670 this.el.addClass('in fade');
26672 this.hoverState = null;
26674 if (this.el.hasClass('fade')) {
26685 //this.el.setXY([0,0]);
26686 this.el.removeClass('in');
26702 * @class Roo.bootstrap.LocationPicker
26703 * @extends Roo.bootstrap.Component
26704 * Bootstrap LocationPicker class
26705 * @cfg {Number} latitude Position when init default 0
26706 * @cfg {Number} longitude Position when init default 0
26707 * @cfg {Number} zoom default 15
26708 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26709 * @cfg {Boolean} mapTypeControl default false
26710 * @cfg {Boolean} disableDoubleClickZoom default false
26711 * @cfg {Boolean} scrollwheel default true
26712 * @cfg {Boolean} streetViewControl default false
26713 * @cfg {Number} radius default 0
26714 * @cfg {String} locationName
26715 * @cfg {Boolean} draggable default true
26716 * @cfg {Boolean} enableAutocomplete default false
26717 * @cfg {Boolean} enableReverseGeocode default true
26718 * @cfg {String} markerTitle
26721 * Create a new LocationPicker
26722 * @param {Object} config The config object
26726 Roo.bootstrap.LocationPicker = function(config){
26728 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26733 * Fires when the picker initialized.
26734 * @param {Roo.bootstrap.LocationPicker} this
26735 * @param {Google Location} location
26739 * @event positionchanged
26740 * Fires when the picker position changed.
26741 * @param {Roo.bootstrap.LocationPicker} this
26742 * @param {Google Location} location
26744 positionchanged : true,
26747 * Fires when the map resize.
26748 * @param {Roo.bootstrap.LocationPicker} this
26753 * Fires when the map show.
26754 * @param {Roo.bootstrap.LocationPicker} this
26759 * Fires when the map hide.
26760 * @param {Roo.bootstrap.LocationPicker} this
26765 * Fires when click the map.
26766 * @param {Roo.bootstrap.LocationPicker} this
26767 * @param {Map event} e
26771 * @event mapRightClick
26772 * Fires when right click the map.
26773 * @param {Roo.bootstrap.LocationPicker} this
26774 * @param {Map event} e
26776 mapRightClick : true,
26778 * @event markerClick
26779 * Fires when click the marker.
26780 * @param {Roo.bootstrap.LocationPicker} this
26781 * @param {Map event} e
26783 markerClick : true,
26785 * @event markerRightClick
26786 * Fires when right click the marker.
26787 * @param {Roo.bootstrap.LocationPicker} this
26788 * @param {Map event} e
26790 markerRightClick : true,
26792 * @event OverlayViewDraw
26793 * Fires when OverlayView Draw
26794 * @param {Roo.bootstrap.LocationPicker} this
26796 OverlayViewDraw : true,
26798 * @event OverlayViewOnAdd
26799 * Fires when OverlayView Draw
26800 * @param {Roo.bootstrap.LocationPicker} this
26802 OverlayViewOnAdd : true,
26804 * @event OverlayViewOnRemove
26805 * Fires when OverlayView Draw
26806 * @param {Roo.bootstrap.LocationPicker} this
26808 OverlayViewOnRemove : true,
26810 * @event OverlayViewShow
26811 * Fires when OverlayView Draw
26812 * @param {Roo.bootstrap.LocationPicker} this
26813 * @param {Pixel} cpx
26815 OverlayViewShow : true,
26817 * @event OverlayViewHide
26818 * Fires when OverlayView Draw
26819 * @param {Roo.bootstrap.LocationPicker} this
26821 OverlayViewHide : true,
26823 * @event loadexception
26824 * Fires when load google lib failed.
26825 * @param {Roo.bootstrap.LocationPicker} this
26827 loadexception : true
26832 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26834 gMapContext: false,
26840 mapTypeControl: false,
26841 disableDoubleClickZoom: false,
26843 streetViewControl: false,
26847 enableAutocomplete: false,
26848 enableReverseGeocode: true,
26851 getAutoCreate: function()
26856 cls: 'roo-location-picker'
26862 initEvents: function(ct, position)
26864 if(!this.el.getWidth() || this.isApplied()){
26868 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26873 initial: function()
26875 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26876 this.fireEvent('loadexception', this);
26880 if(!this.mapTypeId){
26881 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26884 this.gMapContext = this.GMapContext();
26886 this.initOverlayView();
26888 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26892 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26893 _this.setPosition(_this.gMapContext.marker.position);
26896 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26897 _this.fireEvent('mapClick', this, event);
26901 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26902 _this.fireEvent('mapRightClick', this, event);
26906 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26907 _this.fireEvent('markerClick', this, event);
26911 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26912 _this.fireEvent('markerRightClick', this, event);
26916 this.setPosition(this.gMapContext.location);
26918 this.fireEvent('initial', this, this.gMapContext.location);
26921 initOverlayView: function()
26925 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26929 _this.fireEvent('OverlayViewDraw', _this);
26934 _this.fireEvent('OverlayViewOnAdd', _this);
26937 onRemove: function()
26939 _this.fireEvent('OverlayViewOnRemove', _this);
26942 show: function(cpx)
26944 _this.fireEvent('OverlayViewShow', _this, cpx);
26949 _this.fireEvent('OverlayViewHide', _this);
26955 fromLatLngToContainerPixel: function(event)
26957 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26960 isApplied: function()
26962 return this.getGmapContext() == false ? false : true;
26965 getGmapContext: function()
26967 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26970 GMapContext: function()
26972 var position = new google.maps.LatLng(this.latitude, this.longitude);
26974 var _map = new google.maps.Map(this.el.dom, {
26977 mapTypeId: this.mapTypeId,
26978 mapTypeControl: this.mapTypeControl,
26979 disableDoubleClickZoom: this.disableDoubleClickZoom,
26980 scrollwheel: this.scrollwheel,
26981 streetViewControl: this.streetViewControl,
26982 locationName: this.locationName,
26983 draggable: this.draggable,
26984 enableAutocomplete: this.enableAutocomplete,
26985 enableReverseGeocode: this.enableReverseGeocode
26988 var _marker = new google.maps.Marker({
26989 position: position,
26991 title: this.markerTitle,
26992 draggable: this.draggable
26999 location: position,
27000 radius: this.radius,
27001 locationName: this.locationName,
27002 addressComponents: {
27003 formatted_address: null,
27004 addressLine1: null,
27005 addressLine2: null,
27007 streetNumber: null,
27011 stateOrProvince: null
27014 domContainer: this.el.dom,
27015 geodecoder: new google.maps.Geocoder()
27019 drawCircle: function(center, radius, options)
27021 if (this.gMapContext.circle != null) {
27022 this.gMapContext.circle.setMap(null);
27026 options = Roo.apply({}, options, {
27027 strokeColor: "#0000FF",
27028 strokeOpacity: .35,
27030 fillColor: "#0000FF",
27034 options.map = this.gMapContext.map;
27035 options.radius = radius;
27036 options.center = center;
27037 this.gMapContext.circle = new google.maps.Circle(options);
27038 return this.gMapContext.circle;
27044 setPosition: function(location)
27046 this.gMapContext.location = location;
27047 this.gMapContext.marker.setPosition(location);
27048 this.gMapContext.map.panTo(location);
27049 this.drawCircle(location, this.gMapContext.radius, {});
27053 if (this.gMapContext.settings.enableReverseGeocode) {
27054 this.gMapContext.geodecoder.geocode({
27055 latLng: this.gMapContext.location
27056 }, function(results, status) {
27058 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27059 _this.gMapContext.locationName = results[0].formatted_address;
27060 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27062 _this.fireEvent('positionchanged', this, location);
27069 this.fireEvent('positionchanged', this, location);
27074 google.maps.event.trigger(this.gMapContext.map, "resize");
27076 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27078 this.fireEvent('resize', this);
27081 setPositionByLatLng: function(latitude, longitude)
27083 this.setPosition(new google.maps.LatLng(latitude, longitude));
27086 getCurrentPosition: function()
27089 latitude: this.gMapContext.location.lat(),
27090 longitude: this.gMapContext.location.lng()
27094 getAddressName: function()
27096 return this.gMapContext.locationName;
27099 getAddressComponents: function()
27101 return this.gMapContext.addressComponents;
27104 address_component_from_google_geocode: function(address_components)
27108 for (var i = 0; i < address_components.length; i++) {
27109 var component = address_components[i];
27110 if (component.types.indexOf("postal_code") >= 0) {
27111 result.postalCode = component.short_name;
27112 } else if (component.types.indexOf("street_number") >= 0) {
27113 result.streetNumber = component.short_name;
27114 } else if (component.types.indexOf("route") >= 0) {
27115 result.streetName = component.short_name;
27116 } else if (component.types.indexOf("neighborhood") >= 0) {
27117 result.city = component.short_name;
27118 } else if (component.types.indexOf("locality") >= 0) {
27119 result.city = component.short_name;
27120 } else if (component.types.indexOf("sublocality") >= 0) {
27121 result.district = component.short_name;
27122 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27123 result.stateOrProvince = component.short_name;
27124 } else if (component.types.indexOf("country") >= 0) {
27125 result.country = component.short_name;
27129 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27130 result.addressLine2 = "";
27134 setZoomLevel: function(zoom)
27136 this.gMapContext.map.setZoom(zoom);
27149 this.fireEvent('show', this);
27160 this.fireEvent('hide', this);
27165 Roo.apply(Roo.bootstrap.LocationPicker, {
27167 OverlayView : function(map, options)
27169 options = options || {};
27183 * @class Roo.bootstrap.Alert
27184 * @extends Roo.bootstrap.Component
27185 * Bootstrap Alert class
27186 * @cfg {String} title The title of alert
27187 * @cfg {String} html The content of alert
27188 * @cfg {String} weight ( success | info | warning | danger )
27189 * @cfg {String} faicon font-awesomeicon
27192 * Create a new alert
27193 * @param {Object} config The config object
27197 Roo.bootstrap.Alert = function(config){
27198 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27202 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27209 getAutoCreate : function()
27218 cls : 'roo-alert-icon'
27223 cls : 'roo-alert-title',
27228 cls : 'roo-alert-text',
27235 cfg.cn[0].cls += ' fa ' + this.faicon;
27239 cfg.cls += ' alert-' + this.weight;
27245 initEvents: function()
27247 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27250 setTitle : function(str)
27252 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27255 setText : function(str)
27257 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27260 setWeight : function(weight)
27263 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27266 this.weight = weight;
27268 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27271 setIcon : function(icon)
27274 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27277 this.faicon = icon;
27279 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27300 * @class Roo.bootstrap.UploadCropbox
27301 * @extends Roo.bootstrap.Component
27302 * Bootstrap UploadCropbox class
27303 * @cfg {String} emptyText show when image has been loaded
27304 * @cfg {String} rotateNotify show when image too small to rotate
27305 * @cfg {Number} errorTimeout default 3000
27306 * @cfg {Number} minWidth default 300
27307 * @cfg {Number} minHeight default 300
27308 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27309 * @cfg {Boolean} isDocument (true|false) default false
27310 * @cfg {String} url action url
27311 * @cfg {String} paramName default 'imageUpload'
27312 * @cfg {String} method default POST
27313 * @cfg {Boolean} loadMask (true|false) default true
27314 * @cfg {Boolean} loadingText default 'Loading...'
27317 * Create a new UploadCropbox
27318 * @param {Object} config The config object
27321 Roo.bootstrap.UploadCropbox = function(config){
27322 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27326 * @event beforeselectfile
27327 * Fire before select file
27328 * @param {Roo.bootstrap.UploadCropbox} this
27330 "beforeselectfile" : true,
27333 * Fire after initEvent
27334 * @param {Roo.bootstrap.UploadCropbox} this
27339 * Fire after initEvent
27340 * @param {Roo.bootstrap.UploadCropbox} this
27341 * @param {String} data
27346 * Fire when preparing the file data
27347 * @param {Roo.bootstrap.UploadCropbox} this
27348 * @param {Object} file
27353 * Fire when get exception
27354 * @param {Roo.bootstrap.UploadCropbox} this
27355 * @param {XMLHttpRequest} xhr
27357 "exception" : true,
27359 * @event beforeloadcanvas
27360 * Fire before load the canvas
27361 * @param {Roo.bootstrap.UploadCropbox} this
27362 * @param {String} src
27364 "beforeloadcanvas" : true,
27367 * Fire when trash image
27368 * @param {Roo.bootstrap.UploadCropbox} this
27373 * Fire when download the image
27374 * @param {Roo.bootstrap.UploadCropbox} this
27378 * @event footerbuttonclick
27379 * Fire when footerbuttonclick
27380 * @param {Roo.bootstrap.UploadCropbox} this
27381 * @param {String} type
27383 "footerbuttonclick" : true,
27387 * @param {Roo.bootstrap.UploadCropbox} this
27392 * Fire when rotate the image
27393 * @param {Roo.bootstrap.UploadCropbox} this
27394 * @param {String} pos
27399 * Fire when inspect the file
27400 * @param {Roo.bootstrap.UploadCropbox} this
27401 * @param {Object} file
27406 * Fire when xhr upload the file
27407 * @param {Roo.bootstrap.UploadCropbox} this
27408 * @param {Object} data
27413 * Fire when arrange the file data
27414 * @param {Roo.bootstrap.UploadCropbox} this
27415 * @param {Object} formData
27420 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27423 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27425 emptyText : 'Click to upload image',
27426 rotateNotify : 'Image is too small to rotate',
27427 errorTimeout : 3000,
27441 cropType : 'image/jpeg',
27443 canvasLoaded : false,
27444 isDocument : false,
27446 paramName : 'imageUpload',
27448 loadingText : 'Loading...',
27451 getAutoCreate : function()
27455 cls : 'roo-upload-cropbox',
27459 cls : 'roo-upload-cropbox-selector',
27464 cls : 'roo-upload-cropbox-body',
27465 style : 'cursor:pointer',
27469 cls : 'roo-upload-cropbox-preview'
27473 cls : 'roo-upload-cropbox-thumb'
27477 cls : 'roo-upload-cropbox-empty-notify',
27478 html : this.emptyText
27482 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27483 html : this.rotateNotify
27489 cls : 'roo-upload-cropbox-footer',
27492 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27502 onRender : function(ct, position)
27504 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27506 if (this.buttons.length) {
27508 Roo.each(this.buttons, function(bb) {
27510 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27512 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27518 this.maskEl = this.el;
27522 initEvents : function()
27524 this.urlAPI = (window.createObjectURL && window) ||
27525 (window.URL && URL.revokeObjectURL && URL) ||
27526 (window.webkitURL && webkitURL);
27528 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27529 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27531 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27532 this.selectorEl.hide();
27534 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27535 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27537 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27538 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27539 this.thumbEl.hide();
27541 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27542 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27544 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27545 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27546 this.errorEl.hide();
27548 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27549 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27550 this.footerEl.hide();
27552 this.setThumbBoxSize();
27558 this.fireEvent('initial', this);
27565 window.addEventListener("resize", function() { _this.resize(); } );
27567 this.bodyEl.on('click', this.beforeSelectFile, this);
27570 this.bodyEl.on('touchstart', this.onTouchStart, this);
27571 this.bodyEl.on('touchmove', this.onTouchMove, this);
27572 this.bodyEl.on('touchend', this.onTouchEnd, this);
27576 this.bodyEl.on('mousedown', this.onMouseDown, this);
27577 this.bodyEl.on('mousemove', this.onMouseMove, this);
27578 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27579 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27580 Roo.get(document).on('mouseup', this.onMouseUp, this);
27583 this.selectorEl.on('change', this.onFileSelected, this);
27589 this.baseScale = 1;
27591 this.baseRotate = 1;
27592 this.dragable = false;
27593 this.pinching = false;
27596 this.cropData = false;
27597 this.notifyEl.dom.innerHTML = this.emptyText;
27599 this.selectorEl.dom.value = '';
27603 resize : function()
27605 if(this.fireEvent('resize', this) != false){
27606 this.setThumbBoxPosition();
27607 this.setCanvasPosition();
27611 onFooterButtonClick : function(e, el, o, type)
27614 case 'rotate-left' :
27615 this.onRotateLeft(e);
27617 case 'rotate-right' :
27618 this.onRotateRight(e);
27621 this.beforeSelectFile(e);
27636 this.fireEvent('footerbuttonclick', this, type);
27639 beforeSelectFile : function(e)
27641 e.preventDefault();
27643 if(this.fireEvent('beforeselectfile', this) != false){
27644 this.selectorEl.dom.click();
27648 onFileSelected : function(e)
27650 e.preventDefault();
27652 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27656 var file = this.selectorEl.dom.files[0];
27658 if(this.fireEvent('inspect', this, file) != false){
27659 this.prepare(file);
27664 trash : function(e)
27666 this.fireEvent('trash', this);
27669 download : function(e)
27671 this.fireEvent('download', this);
27674 loadCanvas : function(src)
27676 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27680 this.imageEl = document.createElement('img');
27684 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27686 this.imageEl.src = src;
27690 onLoadCanvas : function()
27692 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27693 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27695 this.bodyEl.un('click', this.beforeSelectFile, this);
27697 this.notifyEl.hide();
27698 this.thumbEl.show();
27699 this.footerEl.show();
27701 this.baseRotateLevel();
27703 if(this.isDocument){
27704 this.setThumbBoxSize();
27707 this.setThumbBoxPosition();
27709 this.baseScaleLevel();
27715 this.canvasLoaded = true;
27718 this.maskEl.unmask();
27723 setCanvasPosition : function()
27725 if(!this.canvasEl){
27729 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27730 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27732 this.previewEl.setLeft(pw);
27733 this.previewEl.setTop(ph);
27737 onMouseDown : function(e)
27741 this.dragable = true;
27742 this.pinching = false;
27744 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27745 this.dragable = false;
27749 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27750 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27754 onMouseMove : function(e)
27758 if(!this.canvasLoaded){
27762 if (!this.dragable){
27766 var minX = Math.ceil(this.thumbEl.getLeft(true));
27767 var minY = Math.ceil(this.thumbEl.getTop(true));
27769 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27770 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27772 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27773 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27775 x = x - this.mouseX;
27776 y = y - this.mouseY;
27778 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27779 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27781 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27782 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27784 this.previewEl.setLeft(bgX);
27785 this.previewEl.setTop(bgY);
27787 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27788 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27791 onMouseUp : function(e)
27795 this.dragable = false;
27798 onMouseWheel : function(e)
27802 this.startScale = this.scale;
27804 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27806 if(!this.zoomable()){
27807 this.scale = this.startScale;
27816 zoomable : function()
27818 var minScale = this.thumbEl.getWidth() / this.minWidth;
27820 if(this.minWidth < this.minHeight){
27821 minScale = this.thumbEl.getHeight() / this.minHeight;
27824 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27825 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27829 (this.rotate == 0 || this.rotate == 180) &&
27831 width > this.imageEl.OriginWidth ||
27832 height > this.imageEl.OriginHeight ||
27833 (width < this.minWidth && height < this.minHeight)
27841 (this.rotate == 90 || this.rotate == 270) &&
27843 width > this.imageEl.OriginWidth ||
27844 height > this.imageEl.OriginHeight ||
27845 (width < this.minHeight && height < this.minWidth)
27852 !this.isDocument &&
27853 (this.rotate == 0 || this.rotate == 180) &&
27855 width < this.minWidth ||
27856 width > this.imageEl.OriginWidth ||
27857 height < this.minHeight ||
27858 height > this.imageEl.OriginHeight
27865 !this.isDocument &&
27866 (this.rotate == 90 || this.rotate == 270) &&
27868 width < this.minHeight ||
27869 width > this.imageEl.OriginWidth ||
27870 height < this.minWidth ||
27871 height > this.imageEl.OriginHeight
27881 onRotateLeft : function(e)
27883 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27885 var minScale = this.thumbEl.getWidth() / this.minWidth;
27887 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27888 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27890 this.startScale = this.scale;
27892 while (this.getScaleLevel() < minScale){
27894 this.scale = this.scale + 1;
27896 if(!this.zoomable()){
27901 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27902 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27907 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27914 this.scale = this.startScale;
27916 this.onRotateFail();
27921 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27923 if(this.isDocument){
27924 this.setThumbBoxSize();
27925 this.setThumbBoxPosition();
27926 this.setCanvasPosition();
27931 this.fireEvent('rotate', this, 'left');
27935 onRotateRight : function(e)
27937 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27939 var minScale = this.thumbEl.getWidth() / this.minWidth;
27941 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27942 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27944 this.startScale = this.scale;
27946 while (this.getScaleLevel() < minScale){
27948 this.scale = this.scale + 1;
27950 if(!this.zoomable()){
27955 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27956 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27961 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27968 this.scale = this.startScale;
27970 this.onRotateFail();
27975 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27977 if(this.isDocument){
27978 this.setThumbBoxSize();
27979 this.setThumbBoxPosition();
27980 this.setCanvasPosition();
27985 this.fireEvent('rotate', this, 'right');
27988 onRotateFail : function()
27990 this.errorEl.show(true);
27994 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27999 this.previewEl.dom.innerHTML = '';
28001 var canvasEl = document.createElement("canvas");
28003 var contextEl = canvasEl.getContext("2d");
28005 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28006 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28007 var center = this.imageEl.OriginWidth / 2;
28009 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28010 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28011 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28012 center = this.imageEl.OriginHeight / 2;
28015 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28017 contextEl.translate(center, center);
28018 contextEl.rotate(this.rotate * Math.PI / 180);
28020 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28022 this.canvasEl = document.createElement("canvas");
28024 this.contextEl = this.canvasEl.getContext("2d");
28026 switch (this.rotate) {
28029 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28030 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28032 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28037 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28038 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28040 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28041 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);
28045 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28050 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28051 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28053 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28054 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);
28058 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);
28063 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28064 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28066 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28067 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28071 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);
28078 this.previewEl.appendChild(this.canvasEl);
28080 this.setCanvasPosition();
28085 if(!this.canvasLoaded){
28089 var imageCanvas = document.createElement("canvas");
28091 var imageContext = imageCanvas.getContext("2d");
28093 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28094 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28096 var center = imageCanvas.width / 2;
28098 imageContext.translate(center, center);
28100 imageContext.rotate(this.rotate * Math.PI / 180);
28102 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28104 var canvas = document.createElement("canvas");
28106 var context = canvas.getContext("2d");
28108 canvas.width = this.minWidth;
28109 canvas.height = this.minHeight;
28111 switch (this.rotate) {
28114 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28115 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28117 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28118 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28120 var targetWidth = this.minWidth - 2 * x;
28121 var targetHeight = this.minHeight - 2 * y;
28125 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28126 scale = targetWidth / width;
28129 if(x > 0 && y == 0){
28130 scale = targetHeight / height;
28133 if(x > 0 && y > 0){
28134 scale = targetWidth / width;
28136 if(width < height){
28137 scale = targetHeight / height;
28141 context.scale(scale, scale);
28143 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28144 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28146 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28147 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28149 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28154 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28155 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28157 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28158 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28160 var targetWidth = this.minWidth - 2 * x;
28161 var targetHeight = this.minHeight - 2 * y;
28165 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28166 scale = targetWidth / width;
28169 if(x > 0 && y == 0){
28170 scale = targetHeight / height;
28173 if(x > 0 && y > 0){
28174 scale = targetWidth / width;
28176 if(width < height){
28177 scale = targetHeight / height;
28181 context.scale(scale, scale);
28183 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28184 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28186 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28187 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28189 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28191 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28196 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28197 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (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) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28232 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28234 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28239 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28240 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28242 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28243 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28245 var targetWidth = this.minWidth - 2 * x;
28246 var targetHeight = this.minHeight - 2 * y;
28250 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28251 scale = targetWidth / width;
28254 if(x > 0 && y == 0){
28255 scale = targetHeight / height;
28258 if(x > 0 && y > 0){
28259 scale = targetWidth / width;
28261 if(width < height){
28262 scale = targetHeight / height;
28266 context.scale(scale, scale);
28268 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28269 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28271 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28272 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28274 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28276 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28283 this.cropData = canvas.toDataURL(this.cropType);
28285 if(this.fireEvent('crop', this, this.cropData) !== false){
28286 this.process(this.file, this.cropData);
28293 setThumbBoxSize : function()
28297 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28298 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28299 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28301 this.minWidth = width;
28302 this.minHeight = height;
28304 if(this.rotate == 90 || this.rotate == 270){
28305 this.minWidth = height;
28306 this.minHeight = width;
28311 width = Math.ceil(this.minWidth * height / this.minHeight);
28313 if(this.minWidth > this.minHeight){
28315 height = Math.ceil(this.minHeight * width / this.minWidth);
28318 this.thumbEl.setStyle({
28319 width : width + 'px',
28320 height : height + 'px'
28327 setThumbBoxPosition : function()
28329 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28330 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28332 this.thumbEl.setLeft(x);
28333 this.thumbEl.setTop(y);
28337 baseRotateLevel : function()
28339 this.baseRotate = 1;
28342 typeof(this.exif) != 'undefined' &&
28343 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28344 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28346 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28349 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28353 baseScaleLevel : function()
28357 if(this.isDocument){
28359 if(this.baseRotate == 6 || this.baseRotate == 8){
28361 height = this.thumbEl.getHeight();
28362 this.baseScale = height / this.imageEl.OriginWidth;
28364 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28365 width = this.thumbEl.getWidth();
28366 this.baseScale = width / this.imageEl.OriginHeight;
28372 height = this.thumbEl.getHeight();
28373 this.baseScale = height / this.imageEl.OriginHeight;
28375 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28376 width = this.thumbEl.getWidth();
28377 this.baseScale = width / this.imageEl.OriginWidth;
28383 if(this.baseRotate == 6 || this.baseRotate == 8){
28385 width = this.thumbEl.getHeight();
28386 this.baseScale = width / this.imageEl.OriginHeight;
28388 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28389 height = this.thumbEl.getWidth();
28390 this.baseScale = height / this.imageEl.OriginHeight;
28393 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28394 height = this.thumbEl.getWidth();
28395 this.baseScale = height / this.imageEl.OriginHeight;
28397 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28398 width = this.thumbEl.getHeight();
28399 this.baseScale = width / this.imageEl.OriginWidth;
28406 width = this.thumbEl.getWidth();
28407 this.baseScale = width / this.imageEl.OriginWidth;
28409 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28410 height = this.thumbEl.getHeight();
28411 this.baseScale = height / this.imageEl.OriginHeight;
28414 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28416 height = this.thumbEl.getHeight();
28417 this.baseScale = height / this.imageEl.OriginHeight;
28419 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28420 width = this.thumbEl.getWidth();
28421 this.baseScale = width / this.imageEl.OriginWidth;
28429 getScaleLevel : function()
28431 return this.baseScale * Math.pow(1.1, this.scale);
28434 onTouchStart : function(e)
28436 if(!this.canvasLoaded){
28437 this.beforeSelectFile(e);
28441 var touches = e.browserEvent.touches;
28447 if(touches.length == 1){
28448 this.onMouseDown(e);
28452 if(touches.length != 2){
28458 for(var i = 0, finger; finger = touches[i]; i++){
28459 coords.push(finger.pageX, finger.pageY);
28462 var x = Math.pow(coords[0] - coords[2], 2);
28463 var y = Math.pow(coords[1] - coords[3], 2);
28465 this.startDistance = Math.sqrt(x + y);
28467 this.startScale = this.scale;
28469 this.pinching = true;
28470 this.dragable = false;
28474 onTouchMove : function(e)
28476 if(!this.pinching && !this.dragable){
28480 var touches = e.browserEvent.touches;
28487 this.onMouseMove(e);
28493 for(var i = 0, finger; finger = touches[i]; i++){
28494 coords.push(finger.pageX, finger.pageY);
28497 var x = Math.pow(coords[0] - coords[2], 2);
28498 var y = Math.pow(coords[1] - coords[3], 2);
28500 this.endDistance = Math.sqrt(x + y);
28502 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28504 if(!this.zoomable()){
28505 this.scale = this.startScale;
28513 onTouchEnd : function(e)
28515 this.pinching = false;
28516 this.dragable = false;
28520 process : function(file, crop)
28523 this.maskEl.mask(this.loadingText);
28526 this.xhr = new XMLHttpRequest();
28528 file.xhr = this.xhr;
28530 this.xhr.open(this.method, this.url, true);
28533 "Accept": "application/json",
28534 "Cache-Control": "no-cache",
28535 "X-Requested-With": "XMLHttpRequest"
28538 for (var headerName in headers) {
28539 var headerValue = headers[headerName];
28541 this.xhr.setRequestHeader(headerName, headerValue);
28547 this.xhr.onload = function()
28549 _this.xhrOnLoad(_this.xhr);
28552 this.xhr.onerror = function()
28554 _this.xhrOnError(_this.xhr);
28557 var formData = new FormData();
28559 formData.append('returnHTML', 'NO');
28562 formData.append('crop', crop);
28565 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28566 formData.append(this.paramName, file, file.name);
28569 if(typeof(file.filename) != 'undefined'){
28570 formData.append('filename', file.filename);
28573 if(typeof(file.mimetype) != 'undefined'){
28574 formData.append('mimetype', file.mimetype);
28577 if(this.fireEvent('arrange', this, formData) != false){
28578 this.xhr.send(formData);
28582 xhrOnLoad : function(xhr)
28585 this.maskEl.unmask();
28588 if (xhr.readyState !== 4) {
28589 this.fireEvent('exception', this, xhr);
28593 var response = Roo.decode(xhr.responseText);
28595 if(!response.success){
28596 this.fireEvent('exception', this, xhr);
28600 var response = Roo.decode(xhr.responseText);
28602 this.fireEvent('upload', this, response);
28606 xhrOnError : function()
28609 this.maskEl.unmask();
28612 Roo.log('xhr on error');
28614 var response = Roo.decode(xhr.responseText);
28620 prepare : function(file)
28623 this.maskEl.mask(this.loadingText);
28629 if(typeof(file) === 'string'){
28630 this.loadCanvas(file);
28634 if(!file || !this.urlAPI){
28639 this.cropType = file.type;
28643 if(this.fireEvent('prepare', this, this.file) != false){
28645 var reader = new FileReader();
28647 reader.onload = function (e) {
28648 if (e.target.error) {
28649 Roo.log(e.target.error);
28653 var buffer = e.target.result,
28654 dataView = new DataView(buffer),
28656 maxOffset = dataView.byteLength - 4,
28660 if (dataView.getUint16(0) === 0xffd8) {
28661 while (offset < maxOffset) {
28662 markerBytes = dataView.getUint16(offset);
28664 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28665 markerLength = dataView.getUint16(offset + 2) + 2;
28666 if (offset + markerLength > dataView.byteLength) {
28667 Roo.log('Invalid meta data: Invalid segment size.');
28671 if(markerBytes == 0xffe1){
28672 _this.parseExifData(
28679 offset += markerLength;
28689 var url = _this.urlAPI.createObjectURL(_this.file);
28691 _this.loadCanvas(url);
28696 reader.readAsArrayBuffer(this.file);
28702 parseExifData : function(dataView, offset, length)
28704 var tiffOffset = offset + 10,
28708 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28709 // No Exif data, might be XMP data instead
28713 // Check for the ASCII code for "Exif" (0x45786966):
28714 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28715 // No Exif data, might be XMP data instead
28718 if (tiffOffset + 8 > dataView.byteLength) {
28719 Roo.log('Invalid Exif data: Invalid segment size.');
28722 // Check for the two null bytes:
28723 if (dataView.getUint16(offset + 8) !== 0x0000) {
28724 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28727 // Check the byte alignment:
28728 switch (dataView.getUint16(tiffOffset)) {
28730 littleEndian = true;
28733 littleEndian = false;
28736 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28739 // Check for the TIFF tag marker (0x002A):
28740 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28741 Roo.log('Invalid Exif data: Missing TIFF marker.');
28744 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28745 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28747 this.parseExifTags(
28750 tiffOffset + dirOffset,
28755 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28760 if (dirOffset + 6 > dataView.byteLength) {
28761 Roo.log('Invalid Exif data: Invalid directory offset.');
28764 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28765 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28766 if (dirEndOffset + 4 > dataView.byteLength) {
28767 Roo.log('Invalid Exif data: Invalid directory size.');
28770 for (i = 0; i < tagsNumber; i += 1) {
28774 dirOffset + 2 + 12 * i, // tag offset
28778 // Return the offset to the next directory:
28779 return dataView.getUint32(dirEndOffset, littleEndian);
28782 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28784 var tag = dataView.getUint16(offset, littleEndian);
28786 this.exif[tag] = this.getExifValue(
28790 dataView.getUint16(offset + 2, littleEndian), // tag type
28791 dataView.getUint32(offset + 4, littleEndian), // tag length
28796 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28798 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28807 Roo.log('Invalid Exif data: Invalid tag type.');
28811 tagSize = tagType.size * length;
28812 // Determine if the value is contained in the dataOffset bytes,
28813 // or if the value at the dataOffset is a pointer to the actual data:
28814 dataOffset = tagSize > 4 ?
28815 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28816 if (dataOffset + tagSize > dataView.byteLength) {
28817 Roo.log('Invalid Exif data: Invalid data offset.');
28820 if (length === 1) {
28821 return tagType.getValue(dataView, dataOffset, littleEndian);
28824 for (i = 0; i < length; i += 1) {
28825 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28828 if (tagType.ascii) {
28830 // Concatenate the chars:
28831 for (i = 0; i < values.length; i += 1) {
28833 // Ignore the terminating NULL byte(s):
28834 if (c === '\u0000') {
28846 Roo.apply(Roo.bootstrap.UploadCropbox, {
28848 'Orientation': 0x0112
28852 1: 0, //'top-left',
28854 3: 180, //'bottom-right',
28855 // 4: 'bottom-left',
28857 6: 90, //'right-top',
28858 // 7: 'right-bottom',
28859 8: 270 //'left-bottom'
28863 // byte, 8-bit unsigned int:
28865 getValue: function (dataView, dataOffset) {
28866 return dataView.getUint8(dataOffset);
28870 // ascii, 8-bit byte:
28872 getValue: function (dataView, dataOffset) {
28873 return String.fromCharCode(dataView.getUint8(dataOffset));
28878 // short, 16 bit int:
28880 getValue: function (dataView, dataOffset, littleEndian) {
28881 return dataView.getUint16(dataOffset, littleEndian);
28885 // long, 32 bit int:
28887 getValue: function (dataView, dataOffset, littleEndian) {
28888 return dataView.getUint32(dataOffset, littleEndian);
28892 // rational = two long values, first is numerator, second is denominator:
28894 getValue: function (dataView, dataOffset, littleEndian) {
28895 return dataView.getUint32(dataOffset, littleEndian) /
28896 dataView.getUint32(dataOffset + 4, littleEndian);
28900 // slong, 32 bit signed int:
28902 getValue: function (dataView, dataOffset, littleEndian) {
28903 return dataView.getInt32(dataOffset, littleEndian);
28907 // srational, two slongs, first is numerator, second is denominator:
28909 getValue: function (dataView, dataOffset, littleEndian) {
28910 return dataView.getInt32(dataOffset, littleEndian) /
28911 dataView.getInt32(dataOffset + 4, littleEndian);
28921 cls : 'btn-group roo-upload-cropbox-rotate-left',
28922 action : 'rotate-left',
28926 cls : 'btn btn-default',
28927 html : '<i class="fa fa-undo"></i>'
28933 cls : 'btn-group roo-upload-cropbox-picture',
28934 action : 'picture',
28938 cls : 'btn btn-default',
28939 html : '<i class="fa fa-picture-o"></i>'
28945 cls : 'btn-group roo-upload-cropbox-rotate-right',
28946 action : 'rotate-right',
28950 cls : 'btn btn-default',
28951 html : '<i class="fa fa-repeat"></i>'
28959 cls : 'btn-group roo-upload-cropbox-rotate-left',
28960 action : 'rotate-left',
28964 cls : 'btn btn-default',
28965 html : '<i class="fa fa-undo"></i>'
28971 cls : 'btn-group roo-upload-cropbox-download',
28972 action : 'download',
28976 cls : 'btn btn-default',
28977 html : '<i class="fa fa-download"></i>'
28983 cls : 'btn-group roo-upload-cropbox-crop',
28988 cls : 'btn btn-default',
28989 html : '<i class="fa fa-crop"></i>'
28995 cls : 'btn-group roo-upload-cropbox-trash',
29000 cls : 'btn btn-default',
29001 html : '<i class="fa fa-trash"></i>'
29007 cls : 'btn-group roo-upload-cropbox-rotate-right',
29008 action : 'rotate-right',
29012 cls : 'btn btn-default',
29013 html : '<i class="fa fa-repeat"></i>'
29021 cls : 'btn-group roo-upload-cropbox-rotate-left',
29022 action : 'rotate-left',
29026 cls : 'btn btn-default',
29027 html : '<i class="fa fa-undo"></i>'
29033 cls : 'btn-group roo-upload-cropbox-rotate-right',
29034 action : 'rotate-right',
29038 cls : 'btn btn-default',
29039 html : '<i class="fa fa-repeat"></i>'
29052 * @class Roo.bootstrap.DocumentManager
29053 * @extends Roo.bootstrap.Component
29054 * Bootstrap DocumentManager class
29055 * @cfg {String} paramName default 'imageUpload'
29056 * @cfg {String} toolTipName default 'filename'
29057 * @cfg {String} method default POST
29058 * @cfg {String} url action url
29059 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29060 * @cfg {Boolean} multiple multiple upload default true
29061 * @cfg {Number} thumbSize default 300
29062 * @cfg {String} fieldLabel
29063 * @cfg {Number} labelWidth default 4
29064 * @cfg {String} labelAlign (left|top) default left
29065 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29066 * @cfg {Number} labellg set the width of label (1-12)
29067 * @cfg {Number} labelmd set the width of label (1-12)
29068 * @cfg {Number} labelsm set the width of label (1-12)
29069 * @cfg {Number} labelxs set the width of label (1-12)
29072 * Create a new DocumentManager
29073 * @param {Object} config The config object
29076 Roo.bootstrap.DocumentManager = function(config){
29077 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29080 this.delegates = [];
29085 * Fire when initial the DocumentManager
29086 * @param {Roo.bootstrap.DocumentManager} this
29091 * inspect selected file
29092 * @param {Roo.bootstrap.DocumentManager} this
29093 * @param {File} file
29098 * Fire when xhr load exception
29099 * @param {Roo.bootstrap.DocumentManager} this
29100 * @param {XMLHttpRequest} xhr
29102 "exception" : true,
29104 * @event afterupload
29105 * Fire when xhr load exception
29106 * @param {Roo.bootstrap.DocumentManager} this
29107 * @param {XMLHttpRequest} xhr
29109 "afterupload" : true,
29112 * prepare the form data
29113 * @param {Roo.bootstrap.DocumentManager} this
29114 * @param {Object} formData
29119 * Fire when remove the file
29120 * @param {Roo.bootstrap.DocumentManager} this
29121 * @param {Object} file
29126 * Fire after refresh the file
29127 * @param {Roo.bootstrap.DocumentManager} this
29132 * Fire after click the image
29133 * @param {Roo.bootstrap.DocumentManager} this
29134 * @param {Object} file
29139 * Fire when upload a image and editable set to true
29140 * @param {Roo.bootstrap.DocumentManager} this
29141 * @param {Object} file
29145 * @event beforeselectfile
29146 * Fire before select file
29147 * @param {Roo.bootstrap.DocumentManager} this
29149 "beforeselectfile" : true,
29152 * Fire before process file
29153 * @param {Roo.bootstrap.DocumentManager} this
29154 * @param {Object} file
29158 * @event previewrendered
29159 * Fire when preview rendered
29160 * @param {Roo.bootstrap.DocumentManager} this
29161 * @param {Object} file
29163 "previewrendered" : true,
29166 "previewResize" : true
29171 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29180 paramName : 'imageUpload',
29181 toolTipName : 'filename',
29184 labelAlign : 'left',
29194 getAutoCreate : function()
29196 var managerWidget = {
29198 cls : 'roo-document-manager',
29202 cls : 'roo-document-manager-selector',
29207 cls : 'roo-document-manager-uploader',
29211 cls : 'roo-document-manager-upload-btn',
29212 html : '<i class="fa fa-plus"></i>'
29223 cls : 'column col-md-12',
29228 if(this.fieldLabel.length){
29233 cls : 'column col-md-12',
29234 html : this.fieldLabel
29238 cls : 'column col-md-12',
29243 if(this.labelAlign == 'left'){
29248 html : this.fieldLabel
29257 if(this.labelWidth > 12){
29258 content[0].style = "width: " + this.labelWidth + 'px';
29261 if(this.labelWidth < 13 && this.labelmd == 0){
29262 this.labelmd = this.labelWidth;
29265 if(this.labellg > 0){
29266 content[0].cls += ' col-lg-' + this.labellg;
29267 content[1].cls += ' col-lg-' + (12 - this.labellg);
29270 if(this.labelmd > 0){
29271 content[0].cls += ' col-md-' + this.labelmd;
29272 content[1].cls += ' col-md-' + (12 - this.labelmd);
29275 if(this.labelsm > 0){
29276 content[0].cls += ' col-sm-' + this.labelsm;
29277 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29280 if(this.labelxs > 0){
29281 content[0].cls += ' col-xs-' + this.labelxs;
29282 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29290 cls : 'row clearfix',
29298 initEvents : function()
29300 this.managerEl = this.el.select('.roo-document-manager', true).first();
29301 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29303 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29304 this.selectorEl.hide();
29307 this.selectorEl.attr('multiple', 'multiple');
29310 this.selectorEl.on('change', this.onFileSelected, this);
29312 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29313 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29315 this.uploader.on('click', this.onUploaderClick, this);
29317 this.renderProgressDialog();
29321 window.addEventListener("resize", function() { _this.refresh(); } );
29323 this.fireEvent('initial', this);
29326 renderProgressDialog : function()
29330 this.progressDialog = new Roo.bootstrap.Modal({
29331 cls : 'roo-document-manager-progress-dialog',
29332 allow_close : false,
29343 btnclick : function() {
29344 _this.uploadCancel();
29350 this.progressDialog.render(Roo.get(document.body));
29352 this.progress = new Roo.bootstrap.Progress({
29353 cls : 'roo-document-manager-progress',
29358 this.progress.render(this.progressDialog.getChildContainer());
29360 this.progressBar = new Roo.bootstrap.ProgressBar({
29361 cls : 'roo-document-manager-progress-bar',
29364 aria_valuemax : 12,
29368 this.progressBar.render(this.progress.getChildContainer());
29371 onUploaderClick : function(e)
29373 e.preventDefault();
29375 if(this.fireEvent('beforeselectfile', this) != false){
29376 this.selectorEl.dom.click();
29381 onFileSelected : function(e)
29383 e.preventDefault();
29385 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29389 Roo.each(this.selectorEl.dom.files, function(file){
29390 if(this.fireEvent('inspect', this, file) != false){
29391 this.files.push(file);
29401 this.selectorEl.dom.value = '';
29403 if(!this.files || !this.files.length){
29407 if(this.boxes > 0 && this.files.length > this.boxes){
29408 this.files = this.files.slice(0, this.boxes);
29411 this.uploader.show();
29413 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29414 this.uploader.hide();
29423 Roo.each(this.files, function(file){
29425 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29426 var f = this.renderPreview(file);
29431 if(file.type.indexOf('image') != -1){
29432 this.delegates.push(
29434 _this.process(file);
29435 }).createDelegate(this)
29443 _this.process(file);
29444 }).createDelegate(this)
29449 this.files = files;
29451 this.delegates = this.delegates.concat(docs);
29453 if(!this.delegates.length){
29458 this.progressBar.aria_valuemax = this.delegates.length;
29465 arrange : function()
29467 if(!this.delegates.length){
29468 this.progressDialog.hide();
29473 var delegate = this.delegates.shift();
29475 this.progressDialog.show();
29477 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29479 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29484 refresh : function()
29486 this.uploader.show();
29488 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29489 this.uploader.hide();
29492 Roo.isTouch ? this.closable(false) : this.closable(true);
29494 this.fireEvent('refresh', this);
29497 onRemove : function(e, el, o)
29499 e.preventDefault();
29501 this.fireEvent('remove', this, o);
29505 remove : function(o)
29509 Roo.each(this.files, function(file){
29510 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29519 this.files = files;
29526 Roo.each(this.files, function(file){
29531 file.target.remove();
29540 onClick : function(e, el, o)
29542 e.preventDefault();
29544 this.fireEvent('click', this, o);
29548 closable : function(closable)
29550 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29552 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29564 xhrOnLoad : function(xhr)
29566 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29570 if (xhr.readyState !== 4) {
29572 this.fireEvent('exception', this, xhr);
29576 var response = Roo.decode(xhr.responseText);
29578 if(!response.success){
29580 this.fireEvent('exception', this, xhr);
29584 var file = this.renderPreview(response.data);
29586 this.files.push(file);
29590 this.fireEvent('afterupload', this, xhr);
29594 xhrOnError : function(xhr)
29596 Roo.log('xhr on error');
29598 var response = Roo.decode(xhr.responseText);
29605 process : function(file)
29607 if(this.fireEvent('process', this, file) !== false){
29608 if(this.editable && file.type.indexOf('image') != -1){
29609 this.fireEvent('edit', this, file);
29613 this.uploadStart(file, false);
29620 uploadStart : function(file, crop)
29622 this.xhr = new XMLHttpRequest();
29624 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29629 file.xhr = this.xhr;
29631 this.managerEl.createChild({
29633 cls : 'roo-document-manager-loading',
29637 tooltip : file.name,
29638 cls : 'roo-document-manager-thumb',
29639 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29645 this.xhr.open(this.method, this.url, true);
29648 "Accept": "application/json",
29649 "Cache-Control": "no-cache",
29650 "X-Requested-With": "XMLHttpRequest"
29653 for (var headerName in headers) {
29654 var headerValue = headers[headerName];
29656 this.xhr.setRequestHeader(headerName, headerValue);
29662 this.xhr.onload = function()
29664 _this.xhrOnLoad(_this.xhr);
29667 this.xhr.onerror = function()
29669 _this.xhrOnError(_this.xhr);
29672 var formData = new FormData();
29674 formData.append('returnHTML', 'NO');
29677 formData.append('crop', crop);
29680 formData.append(this.paramName, file, file.name);
29687 if(this.fireEvent('prepare', this, formData, options) != false){
29689 if(options.manually){
29693 this.xhr.send(formData);
29697 this.uploadCancel();
29700 uploadCancel : function()
29706 this.delegates = [];
29708 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29715 renderPreview : function(file)
29717 if(typeof(file.target) != 'undefined' && file.target){
29721 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29723 var previewEl = this.managerEl.createChild({
29725 cls : 'roo-document-manager-preview',
29729 tooltip : file[this.toolTipName],
29730 cls : 'roo-document-manager-thumb',
29731 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29736 html : '<i class="fa fa-times-circle"></i>'
29741 var close = previewEl.select('button.close', true).first();
29743 close.on('click', this.onRemove, this, file);
29745 file.target = previewEl;
29747 var image = previewEl.select('img', true).first();
29751 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29753 image.on('click', this.onClick, this, file);
29755 this.fireEvent('previewrendered', this, file);
29761 onPreviewLoad : function(file, image)
29763 if(typeof(file.target) == 'undefined' || !file.target){
29767 var width = image.dom.naturalWidth || image.dom.width;
29768 var height = image.dom.naturalHeight || image.dom.height;
29770 if(!this.previewResize) {
29774 if(width > height){
29775 file.target.addClass('wide');
29779 file.target.addClass('tall');
29784 uploadFromSource : function(file, crop)
29786 this.xhr = new XMLHttpRequest();
29788 this.managerEl.createChild({
29790 cls : 'roo-document-manager-loading',
29794 tooltip : file.name,
29795 cls : 'roo-document-manager-thumb',
29796 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29802 this.xhr.open(this.method, this.url, true);
29805 "Accept": "application/json",
29806 "Cache-Control": "no-cache",
29807 "X-Requested-With": "XMLHttpRequest"
29810 for (var headerName in headers) {
29811 var headerValue = headers[headerName];
29813 this.xhr.setRequestHeader(headerName, headerValue);
29819 this.xhr.onload = function()
29821 _this.xhrOnLoad(_this.xhr);
29824 this.xhr.onerror = function()
29826 _this.xhrOnError(_this.xhr);
29829 var formData = new FormData();
29831 formData.append('returnHTML', 'NO');
29833 formData.append('crop', crop);
29835 if(typeof(file.filename) != 'undefined'){
29836 formData.append('filename', file.filename);
29839 if(typeof(file.mimetype) != 'undefined'){
29840 formData.append('mimetype', file.mimetype);
29845 if(this.fireEvent('prepare', this, formData) != false){
29846 this.xhr.send(formData);
29856 * @class Roo.bootstrap.DocumentViewer
29857 * @extends Roo.bootstrap.Component
29858 * Bootstrap DocumentViewer class
29859 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29860 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29863 * Create a new DocumentViewer
29864 * @param {Object} config The config object
29867 Roo.bootstrap.DocumentViewer = function(config){
29868 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29873 * Fire after initEvent
29874 * @param {Roo.bootstrap.DocumentViewer} this
29880 * @param {Roo.bootstrap.DocumentViewer} this
29885 * Fire after download button
29886 * @param {Roo.bootstrap.DocumentViewer} this
29891 * Fire after trash button
29892 * @param {Roo.bootstrap.DocumentViewer} this
29899 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29901 showDownload : true,
29905 getAutoCreate : function()
29909 cls : 'roo-document-viewer',
29913 cls : 'roo-document-viewer-body',
29917 cls : 'roo-document-viewer-thumb',
29921 cls : 'roo-document-viewer-image'
29929 cls : 'roo-document-viewer-footer',
29932 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29936 cls : 'btn-group roo-document-viewer-download',
29940 cls : 'btn btn-default',
29941 html : '<i class="fa fa-download"></i>'
29947 cls : 'btn-group roo-document-viewer-trash',
29951 cls : 'btn btn-default',
29952 html : '<i class="fa fa-trash"></i>'
29965 initEvents : function()
29967 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29968 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29970 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29971 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29973 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29974 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29976 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29977 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29979 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29980 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29982 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29983 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29985 this.bodyEl.on('click', this.onClick, this);
29986 this.downloadBtn.on('click', this.onDownload, this);
29987 this.trashBtn.on('click', this.onTrash, this);
29989 this.downloadBtn.hide();
29990 this.trashBtn.hide();
29992 if(this.showDownload){
29993 this.downloadBtn.show();
29996 if(this.showTrash){
29997 this.trashBtn.show();
30000 if(!this.showDownload && !this.showTrash) {
30001 this.footerEl.hide();
30006 initial : function()
30008 this.fireEvent('initial', this);
30012 onClick : function(e)
30014 e.preventDefault();
30016 this.fireEvent('click', this);
30019 onDownload : function(e)
30021 e.preventDefault();
30023 this.fireEvent('download', this);
30026 onTrash : function(e)
30028 e.preventDefault();
30030 this.fireEvent('trash', this);
30042 * @class Roo.bootstrap.NavProgressBar
30043 * @extends Roo.bootstrap.Component
30044 * Bootstrap NavProgressBar class
30047 * Create a new nav progress bar
30048 * @param {Object} config The config object
30051 Roo.bootstrap.NavProgressBar = function(config){
30052 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30054 this.bullets = this.bullets || [];
30056 // Roo.bootstrap.NavProgressBar.register(this);
30060 * Fires when the active item changes
30061 * @param {Roo.bootstrap.NavProgressBar} this
30062 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30063 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30070 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30075 getAutoCreate : function()
30077 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30081 cls : 'roo-navigation-bar-group',
30085 cls : 'roo-navigation-top-bar'
30089 cls : 'roo-navigation-bullets-bar',
30093 cls : 'roo-navigation-bar'
30100 cls : 'roo-navigation-bottom-bar'
30110 initEvents: function()
30115 onRender : function(ct, position)
30117 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30119 if(this.bullets.length){
30120 Roo.each(this.bullets, function(b){
30129 addItem : function(cfg)
30131 var item = new Roo.bootstrap.NavProgressItem(cfg);
30133 item.parentId = this.id;
30134 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30137 var top = new Roo.bootstrap.Element({
30139 cls : 'roo-navigation-bar-text'
30142 var bottom = new Roo.bootstrap.Element({
30144 cls : 'roo-navigation-bar-text'
30147 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30148 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30150 var topText = new Roo.bootstrap.Element({
30152 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30155 var bottomText = new Roo.bootstrap.Element({
30157 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30160 topText.onRender(top.el, null);
30161 bottomText.onRender(bottom.el, null);
30164 item.bottomEl = bottom;
30167 this.barItems.push(item);
30172 getActive : function()
30174 var active = false;
30176 Roo.each(this.barItems, function(v){
30178 if (!v.isActive()) {
30190 setActiveItem : function(item)
30194 Roo.each(this.barItems, function(v){
30195 if (v.rid == item.rid) {
30199 if (v.isActive()) {
30200 v.setActive(false);
30205 item.setActive(true);
30207 this.fireEvent('changed', this, item, prev);
30210 getBarItem: function(rid)
30214 Roo.each(this.barItems, function(e) {
30215 if (e.rid != rid) {
30226 indexOfItem : function(item)
30230 Roo.each(this.barItems, function(v, i){
30232 if (v.rid != item.rid) {
30243 setActiveNext : function()
30245 var i = this.indexOfItem(this.getActive());
30247 if (i > this.barItems.length) {
30251 this.setActiveItem(this.barItems[i+1]);
30254 setActivePrev : function()
30256 var i = this.indexOfItem(this.getActive());
30262 this.setActiveItem(this.barItems[i-1]);
30265 format : function()
30267 if(!this.barItems.length){
30271 var width = 100 / this.barItems.length;
30273 Roo.each(this.barItems, function(i){
30274 i.el.setStyle('width', width + '%');
30275 i.topEl.el.setStyle('width', width + '%');
30276 i.bottomEl.el.setStyle('width', width + '%');
30285 * Nav Progress Item
30290 * @class Roo.bootstrap.NavProgressItem
30291 * @extends Roo.bootstrap.Component
30292 * Bootstrap NavProgressItem class
30293 * @cfg {String} rid the reference id
30294 * @cfg {Boolean} active (true|false) Is item active default false
30295 * @cfg {Boolean} disabled (true|false) Is item active default false
30296 * @cfg {String} html
30297 * @cfg {String} position (top|bottom) text position default bottom
30298 * @cfg {String} icon show icon instead of number
30301 * Create a new NavProgressItem
30302 * @param {Object} config The config object
30304 Roo.bootstrap.NavProgressItem = function(config){
30305 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30310 * The raw click event for the entire grid.
30311 * @param {Roo.bootstrap.NavProgressItem} this
30312 * @param {Roo.EventObject} e
30319 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30325 position : 'bottom',
30328 getAutoCreate : function()
30330 var iconCls = 'roo-navigation-bar-item-icon';
30332 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30336 cls: 'roo-navigation-bar-item',
30346 cfg.cls += ' active';
30349 cfg.cls += ' disabled';
30355 disable : function()
30357 this.setDisabled(true);
30360 enable : function()
30362 this.setDisabled(false);
30365 initEvents: function()
30367 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30369 this.iconEl.on('click', this.onClick, this);
30372 onClick : function(e)
30374 e.preventDefault();
30380 if(this.fireEvent('click', this, e) === false){
30384 this.parent().setActiveItem(this);
30387 isActive: function ()
30389 return this.active;
30392 setActive : function(state)
30394 if(this.active == state){
30398 this.active = state;
30401 this.el.addClass('active');
30405 this.el.removeClass('active');
30410 setDisabled : function(state)
30412 if(this.disabled == state){
30416 this.disabled = state;
30419 this.el.addClass('disabled');
30423 this.el.removeClass('disabled');
30426 tooltipEl : function()
30428 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30441 * @class Roo.bootstrap.FieldLabel
30442 * @extends Roo.bootstrap.Component
30443 * Bootstrap FieldLabel class
30444 * @cfg {String} html contents of the element
30445 * @cfg {String} tag tag of the element default label
30446 * @cfg {String} cls class of the element
30447 * @cfg {String} target label target
30448 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30449 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30450 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30451 * @cfg {String} iconTooltip default "This field is required"
30452 * @cfg {String} indicatorpos (left|right) default left
30455 * Create a new FieldLabel
30456 * @param {Object} config The config object
30459 Roo.bootstrap.FieldLabel = function(config){
30460 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30465 * Fires after the field has been marked as invalid.
30466 * @param {Roo.form.FieldLabel} this
30467 * @param {String} msg The validation message
30472 * Fires after the field has been validated with no errors.
30473 * @param {Roo.form.FieldLabel} this
30479 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30486 invalidClass : 'has-warning',
30487 validClass : 'has-success',
30488 iconTooltip : 'This field is required',
30489 indicatorpos : 'left',
30491 getAutoCreate : function(){
30494 if (!this.allowBlank) {
30500 cls : 'roo-bootstrap-field-label ' + this.cls,
30505 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30506 tooltip : this.iconTooltip
30515 if(this.indicatorpos == 'right'){
30518 cls : 'roo-bootstrap-field-label ' + this.cls,
30527 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30528 tooltip : this.iconTooltip
30537 initEvents: function()
30539 Roo.bootstrap.Element.superclass.initEvents.call(this);
30541 this.indicator = this.indicatorEl();
30543 if(this.indicator){
30544 this.indicator.removeClass('visible');
30545 this.indicator.addClass('invisible');
30548 Roo.bootstrap.FieldLabel.register(this);
30551 indicatorEl : function()
30553 var indicator = this.el.select('i.roo-required-indicator',true).first();
30564 * Mark this field as valid
30566 markValid : function()
30568 if(this.indicator){
30569 this.indicator.removeClass('visible');
30570 this.indicator.addClass('invisible');
30572 if (Roo.bootstrap.version == 3) {
30573 this.el.removeClass(this.invalidClass);
30574 this.el.addClass(this.validClass);
30576 this.el.removeClass('is-invalid');
30577 this.el.addClass('is-valid');
30581 this.fireEvent('valid', this);
30585 * Mark this field as invalid
30586 * @param {String} msg The validation message
30588 markInvalid : function(msg)
30590 if(this.indicator){
30591 this.indicator.removeClass('invisible');
30592 this.indicator.addClass('visible');
30594 if (Roo.bootstrap.version == 3) {
30595 this.el.removeClass(this.validClass);
30596 this.el.addClass(this.invalidClass);
30598 this.el.removeClass('is-valid');
30599 this.el.addClass('is-invalid');
30603 this.fireEvent('invalid', this, msg);
30609 Roo.apply(Roo.bootstrap.FieldLabel, {
30614 * register a FieldLabel Group
30615 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30617 register : function(label)
30619 if(this.groups.hasOwnProperty(label.target)){
30623 this.groups[label.target] = label;
30627 * fetch a FieldLabel Group based on the target
30628 * @param {string} target
30629 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30631 get: function(target) {
30632 if (typeof(this.groups[target]) == 'undefined') {
30636 return this.groups[target] ;
30645 * page DateSplitField.
30651 * @class Roo.bootstrap.DateSplitField
30652 * @extends Roo.bootstrap.Component
30653 * Bootstrap DateSplitField class
30654 * @cfg {string} fieldLabel - the label associated
30655 * @cfg {Number} labelWidth set the width of label (0-12)
30656 * @cfg {String} labelAlign (top|left)
30657 * @cfg {Boolean} dayAllowBlank (true|false) default false
30658 * @cfg {Boolean} monthAllowBlank (true|false) default false
30659 * @cfg {Boolean} yearAllowBlank (true|false) default false
30660 * @cfg {string} dayPlaceholder
30661 * @cfg {string} monthPlaceholder
30662 * @cfg {string} yearPlaceholder
30663 * @cfg {string} dayFormat default 'd'
30664 * @cfg {string} monthFormat default 'm'
30665 * @cfg {string} yearFormat default 'Y'
30666 * @cfg {Number} labellg set the width of label (1-12)
30667 * @cfg {Number} labelmd set the width of label (1-12)
30668 * @cfg {Number} labelsm set the width of label (1-12)
30669 * @cfg {Number} labelxs set the width of label (1-12)
30673 * Create a new DateSplitField
30674 * @param {Object} config The config object
30677 Roo.bootstrap.DateSplitField = function(config){
30678 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30684 * getting the data of years
30685 * @param {Roo.bootstrap.DateSplitField} this
30686 * @param {Object} years
30691 * getting the data of days
30692 * @param {Roo.bootstrap.DateSplitField} this
30693 * @param {Object} days
30698 * Fires after the field has been marked as invalid.
30699 * @param {Roo.form.Field} this
30700 * @param {String} msg The validation message
30705 * Fires after the field has been validated with no errors.
30706 * @param {Roo.form.Field} this
30712 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30715 labelAlign : 'top',
30717 dayAllowBlank : false,
30718 monthAllowBlank : false,
30719 yearAllowBlank : false,
30720 dayPlaceholder : '',
30721 monthPlaceholder : '',
30722 yearPlaceholder : '',
30726 isFormField : true,
30732 getAutoCreate : function()
30736 cls : 'row roo-date-split-field-group',
30741 cls : 'form-hidden-field roo-date-split-field-group-value',
30747 var labelCls = 'col-md-12';
30748 var contentCls = 'col-md-4';
30750 if(this.fieldLabel){
30754 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30758 html : this.fieldLabel
30763 if(this.labelAlign == 'left'){
30765 if(this.labelWidth > 12){
30766 label.style = "width: " + this.labelWidth + 'px';
30769 if(this.labelWidth < 13 && this.labelmd == 0){
30770 this.labelmd = this.labelWidth;
30773 if(this.labellg > 0){
30774 labelCls = ' col-lg-' + this.labellg;
30775 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30778 if(this.labelmd > 0){
30779 labelCls = ' col-md-' + this.labelmd;
30780 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30783 if(this.labelsm > 0){
30784 labelCls = ' col-sm-' + this.labelsm;
30785 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30788 if(this.labelxs > 0){
30789 labelCls = ' col-xs-' + this.labelxs;
30790 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30794 label.cls += ' ' + labelCls;
30796 cfg.cn.push(label);
30799 Roo.each(['day', 'month', 'year'], function(t){
30802 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30809 inputEl: function ()
30811 return this.el.select('.roo-date-split-field-group-value', true).first();
30814 onRender : function(ct, position)
30818 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30820 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30822 this.dayField = new Roo.bootstrap.ComboBox({
30823 allowBlank : this.dayAllowBlank,
30824 alwaysQuery : true,
30825 displayField : 'value',
30828 forceSelection : true,
30830 placeholder : this.dayPlaceholder,
30831 selectOnFocus : true,
30832 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30833 triggerAction : 'all',
30835 valueField : 'value',
30836 store : new Roo.data.SimpleStore({
30837 data : (function() {
30839 _this.fireEvent('days', _this, days);
30842 fields : [ 'value' ]
30845 select : function (_self, record, index)
30847 _this.setValue(_this.getValue());
30852 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30854 this.monthField = new Roo.bootstrap.MonthField({
30855 after : '<i class=\"fa fa-calendar\"></i>',
30856 allowBlank : this.monthAllowBlank,
30857 placeholder : this.monthPlaceholder,
30860 render : function (_self)
30862 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30863 e.preventDefault();
30867 select : function (_self, oldvalue, newvalue)
30869 _this.setValue(_this.getValue());
30874 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30876 this.yearField = new Roo.bootstrap.ComboBox({
30877 allowBlank : this.yearAllowBlank,
30878 alwaysQuery : true,
30879 displayField : 'value',
30882 forceSelection : true,
30884 placeholder : this.yearPlaceholder,
30885 selectOnFocus : true,
30886 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30887 triggerAction : 'all',
30889 valueField : 'value',
30890 store : new Roo.data.SimpleStore({
30891 data : (function() {
30893 _this.fireEvent('years', _this, years);
30896 fields : [ 'value' ]
30899 select : function (_self, record, index)
30901 _this.setValue(_this.getValue());
30906 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30909 setValue : function(v, format)
30911 this.inputEl.dom.value = v;
30913 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30915 var d = Date.parseDate(v, f);
30922 this.setDay(d.format(this.dayFormat));
30923 this.setMonth(d.format(this.monthFormat));
30924 this.setYear(d.format(this.yearFormat));
30931 setDay : function(v)
30933 this.dayField.setValue(v);
30934 this.inputEl.dom.value = this.getValue();
30939 setMonth : function(v)
30941 this.monthField.setValue(v, true);
30942 this.inputEl.dom.value = this.getValue();
30947 setYear : function(v)
30949 this.yearField.setValue(v);
30950 this.inputEl.dom.value = this.getValue();
30955 getDay : function()
30957 return this.dayField.getValue();
30960 getMonth : function()
30962 return this.monthField.getValue();
30965 getYear : function()
30967 return this.yearField.getValue();
30970 getValue : function()
30972 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30974 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30984 this.inputEl.dom.value = '';
30989 validate : function()
30991 var d = this.dayField.validate();
30992 var m = this.monthField.validate();
30993 var y = this.yearField.validate();
30998 (!this.dayAllowBlank && !d) ||
30999 (!this.monthAllowBlank && !m) ||
31000 (!this.yearAllowBlank && !y)
31005 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31014 this.markInvalid();
31019 markValid : function()
31022 var label = this.el.select('label', true).first();
31023 var icon = this.el.select('i.fa-star', true).first();
31029 this.fireEvent('valid', this);
31033 * Mark this field as invalid
31034 * @param {String} msg The validation message
31036 markInvalid : function(msg)
31039 var label = this.el.select('label', true).first();
31040 var icon = this.el.select('i.fa-star', true).first();
31042 if(label && !icon){
31043 this.el.select('.roo-date-split-field-label', true).createChild({
31045 cls : 'text-danger fa fa-lg fa-star',
31046 tooltip : 'This field is required',
31047 style : 'margin-right:5px;'
31051 this.fireEvent('invalid', this, msg);
31054 clearInvalid : function()
31056 var label = this.el.select('label', true).first();
31057 var icon = this.el.select('i.fa-star', true).first();
31063 this.fireEvent('valid', this);
31066 getName: function()
31076 * http://masonry.desandro.com
31078 * The idea is to render all the bricks based on vertical width...
31080 * The original code extends 'outlayer' - we might need to use that....
31086 * @class Roo.bootstrap.LayoutMasonry
31087 * @extends Roo.bootstrap.Component
31088 * Bootstrap Layout Masonry class
31091 * Create a new Element
31092 * @param {Object} config The config object
31095 Roo.bootstrap.LayoutMasonry = function(config){
31097 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31101 Roo.bootstrap.LayoutMasonry.register(this);
31107 * Fire after layout the items
31108 * @param {Roo.bootstrap.LayoutMasonry} this
31109 * @param {Roo.EventObject} e
31116 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31119 * @cfg {Boolean} isLayoutInstant = no animation?
31121 isLayoutInstant : false, // needed?
31124 * @cfg {Number} boxWidth width of the columns
31129 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31134 * @cfg {Number} padWidth padding below box..
31139 * @cfg {Number} gutter gutter width..
31144 * @cfg {Number} maxCols maximum number of columns
31150 * @cfg {Boolean} isAutoInitial defalut true
31152 isAutoInitial : true,
31157 * @cfg {Boolean} isHorizontal defalut false
31159 isHorizontal : false,
31161 currentSize : null,
31167 bricks: null, //CompositeElement
31171 _isLayoutInited : false,
31173 // isAlternative : false, // only use for vertical layout...
31176 * @cfg {Number} alternativePadWidth padding below box..
31178 alternativePadWidth : 50,
31180 selectedBrick : [],
31182 getAutoCreate : function(){
31184 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31188 cls: 'blog-masonary-wrapper ' + this.cls,
31190 cls : 'mas-boxes masonary'
31197 getChildContainer: function( )
31199 if (this.boxesEl) {
31200 return this.boxesEl;
31203 this.boxesEl = this.el.select('.mas-boxes').first();
31205 return this.boxesEl;
31209 initEvents : function()
31213 if(this.isAutoInitial){
31214 Roo.log('hook children rendered');
31215 this.on('childrenrendered', function() {
31216 Roo.log('children rendered');
31222 initial : function()
31224 this.selectedBrick = [];
31226 this.currentSize = this.el.getBox(true);
31228 Roo.EventManager.onWindowResize(this.resize, this);
31230 if(!this.isAutoInitial){
31238 //this.layout.defer(500,this);
31242 resize : function()
31244 var cs = this.el.getBox(true);
31247 this.currentSize.width == cs.width &&
31248 this.currentSize.x == cs.x &&
31249 this.currentSize.height == cs.height &&
31250 this.currentSize.y == cs.y
31252 Roo.log("no change in with or X or Y");
31256 this.currentSize = cs;
31262 layout : function()
31264 this._resetLayout();
31266 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31268 this.layoutItems( isInstant );
31270 this._isLayoutInited = true;
31272 this.fireEvent('layout', this);
31276 _resetLayout : function()
31278 if(this.isHorizontal){
31279 this.horizontalMeasureColumns();
31283 this.verticalMeasureColumns();
31287 verticalMeasureColumns : function()
31289 this.getContainerWidth();
31291 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31292 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31296 var boxWidth = this.boxWidth + this.padWidth;
31298 if(this.containerWidth < this.boxWidth){
31299 boxWidth = this.containerWidth
31302 var containerWidth = this.containerWidth;
31304 var cols = Math.floor(containerWidth / boxWidth);
31306 this.cols = Math.max( cols, 1 );
31308 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31310 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31312 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31314 this.colWidth = boxWidth + avail - this.padWidth;
31316 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31317 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31320 horizontalMeasureColumns : function()
31322 this.getContainerWidth();
31324 var boxWidth = this.boxWidth;
31326 if(this.containerWidth < boxWidth){
31327 boxWidth = this.containerWidth;
31330 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31332 this.el.setHeight(boxWidth);
31336 getContainerWidth : function()
31338 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31341 layoutItems : function( isInstant )
31343 Roo.log(this.bricks);
31345 var items = Roo.apply([], this.bricks);
31347 if(this.isHorizontal){
31348 this._horizontalLayoutItems( items , isInstant );
31352 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31353 // this._verticalAlternativeLayoutItems( items , isInstant );
31357 this._verticalLayoutItems( items , isInstant );
31361 _verticalLayoutItems : function ( items , isInstant)
31363 if ( !items || !items.length ) {
31368 ['xs', 'xs', 'xs', 'tall'],
31369 ['xs', 'xs', 'tall'],
31370 ['xs', 'xs', 'sm'],
31371 ['xs', 'xs', 'xs'],
31377 ['sm', 'xs', 'xs'],
31381 ['tall', 'xs', 'xs', 'xs'],
31382 ['tall', 'xs', 'xs'],
31394 Roo.each(items, function(item, k){
31396 switch (item.size) {
31397 // these layouts take up a full box,
31408 boxes.push([item]);
31431 var filterPattern = function(box, length)
31439 var pattern = box.slice(0, length);
31443 Roo.each(pattern, function(i){
31444 format.push(i.size);
31447 Roo.each(standard, function(s){
31449 if(String(s) != String(format)){
31458 if(!match && length == 1){
31463 filterPattern(box, length - 1);
31467 queue.push(pattern);
31469 box = box.slice(length, box.length);
31471 filterPattern(box, 4);
31477 Roo.each(boxes, function(box, k){
31483 if(box.length == 1){
31488 filterPattern(box, 4);
31492 this._processVerticalLayoutQueue( queue, isInstant );
31496 // _verticalAlternativeLayoutItems : function( items , isInstant )
31498 // if ( !items || !items.length ) {
31502 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31506 _horizontalLayoutItems : function ( items , isInstant)
31508 if ( !items || !items.length || items.length < 3) {
31514 var eItems = items.slice(0, 3);
31516 items = items.slice(3, items.length);
31519 ['xs', 'xs', 'xs', 'wide'],
31520 ['xs', 'xs', 'wide'],
31521 ['xs', 'xs', 'sm'],
31522 ['xs', 'xs', 'xs'],
31528 ['sm', 'xs', 'xs'],
31532 ['wide', 'xs', 'xs', 'xs'],
31533 ['wide', 'xs', 'xs'],
31546 Roo.each(items, function(item, k){
31548 switch (item.size) {
31559 boxes.push([item]);
31583 var filterPattern = function(box, length)
31591 var pattern = box.slice(0, length);
31595 Roo.each(pattern, function(i){
31596 format.push(i.size);
31599 Roo.each(standard, function(s){
31601 if(String(s) != String(format)){
31610 if(!match && length == 1){
31615 filterPattern(box, length - 1);
31619 queue.push(pattern);
31621 box = box.slice(length, box.length);
31623 filterPattern(box, 4);
31629 Roo.each(boxes, function(box, k){
31635 if(box.length == 1){
31640 filterPattern(box, 4);
31647 var pos = this.el.getBox(true);
31651 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31653 var hit_end = false;
31655 Roo.each(queue, function(box){
31659 Roo.each(box, function(b){
31661 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31671 Roo.each(box, function(b){
31673 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31676 mx = Math.max(mx, b.x);
31680 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31684 Roo.each(box, function(b){
31686 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31700 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31703 /** Sets position of item in DOM
31704 * @param {Element} item
31705 * @param {Number} x - horizontal position
31706 * @param {Number} y - vertical position
31707 * @param {Boolean} isInstant - disables transitions
31709 _processVerticalLayoutQueue : function( queue, isInstant )
31711 var pos = this.el.getBox(true);
31716 for (var i = 0; i < this.cols; i++){
31720 Roo.each(queue, function(box, k){
31722 var col = k % this.cols;
31724 Roo.each(box, function(b,kk){
31726 b.el.position('absolute');
31728 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31729 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31731 if(b.size == 'md-left' || b.size == 'md-right'){
31732 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31733 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31736 b.el.setWidth(width);
31737 b.el.setHeight(height);
31739 b.el.select('iframe',true).setSize(width,height);
31743 for (var i = 0; i < this.cols; i++){
31745 if(maxY[i] < maxY[col]){
31750 col = Math.min(col, i);
31754 x = pos.x + col * (this.colWidth + this.padWidth);
31758 var positions = [];
31760 switch (box.length){
31762 positions = this.getVerticalOneBoxColPositions(x, y, box);
31765 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31768 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31771 positions = this.getVerticalFourBoxColPositions(x, y, box);
31777 Roo.each(box, function(b,kk){
31779 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31781 var sz = b.el.getSize();
31783 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31791 for (var i = 0; i < this.cols; i++){
31792 mY = Math.max(mY, maxY[i]);
31795 this.el.setHeight(mY - pos.y);
31799 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31801 // var pos = this.el.getBox(true);
31804 // var maxX = pos.right;
31806 // var maxHeight = 0;
31808 // Roo.each(items, function(item, k){
31812 // item.el.position('absolute');
31814 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31816 // item.el.setWidth(width);
31818 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31820 // item.el.setHeight(height);
31823 // item.el.setXY([x, y], isInstant ? false : true);
31825 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31828 // y = y + height + this.alternativePadWidth;
31830 // maxHeight = maxHeight + height + this.alternativePadWidth;
31834 // this.el.setHeight(maxHeight);
31838 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31840 var pos = this.el.getBox(true);
31845 var maxX = pos.right;
31847 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31849 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31851 Roo.each(queue, function(box, k){
31853 Roo.each(box, function(b, kk){
31855 b.el.position('absolute');
31857 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31858 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31860 if(b.size == 'md-left' || b.size == 'md-right'){
31861 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31862 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31865 b.el.setWidth(width);
31866 b.el.setHeight(height);
31874 var positions = [];
31876 switch (box.length){
31878 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31881 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31884 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31887 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31893 Roo.each(box, function(b,kk){
31895 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31897 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31905 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31907 Roo.each(eItems, function(b,k){
31909 b.size = (k == 0) ? 'sm' : 'xs';
31910 b.x = (k == 0) ? 2 : 1;
31911 b.y = (k == 0) ? 2 : 1;
31913 b.el.position('absolute');
31915 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31917 b.el.setWidth(width);
31919 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31921 b.el.setHeight(height);
31925 var positions = [];
31928 x : maxX - this.unitWidth * 2 - this.gutter,
31933 x : maxX - this.unitWidth,
31934 y : minY + (this.unitWidth + this.gutter) * 2
31938 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31942 Roo.each(eItems, function(b,k){
31944 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31950 getVerticalOneBoxColPositions : function(x, y, box)
31954 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31956 if(box[0].size == 'md-left'){
31960 if(box[0].size == 'md-right'){
31965 x : x + (this.unitWidth + this.gutter) * rand,
31972 getVerticalTwoBoxColPositions : function(x, y, box)
31976 if(box[0].size == 'xs'){
31980 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31984 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31998 x : x + (this.unitWidth + this.gutter) * 2,
31999 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32006 getVerticalThreeBoxColPositions : function(x, y, box)
32010 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32018 x : x + (this.unitWidth + this.gutter) * 1,
32023 x : x + (this.unitWidth + this.gutter) * 2,
32031 if(box[0].size == 'xs' && box[1].size == 'xs'){
32040 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32044 x : x + (this.unitWidth + this.gutter) * 1,
32058 x : x + (this.unitWidth + this.gutter) * 2,
32063 x : x + (this.unitWidth + this.gutter) * 2,
32064 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32071 getVerticalFourBoxColPositions : function(x, y, box)
32075 if(box[0].size == 'xs'){
32084 y : y + (this.unitHeight + this.gutter) * 1
32089 y : y + (this.unitHeight + this.gutter) * 2
32093 x : x + (this.unitWidth + this.gutter) * 1,
32107 x : x + (this.unitWidth + this.gutter) * 2,
32112 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32113 y : y + (this.unitHeight + this.gutter) * 1
32117 x : x + (this.unitWidth + this.gutter) * 2,
32118 y : y + (this.unitWidth + this.gutter) * 2
32125 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32129 if(box[0].size == 'md-left'){
32131 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32138 if(box[0].size == 'md-right'){
32140 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32141 y : minY + (this.unitWidth + this.gutter) * 1
32147 var rand = Math.floor(Math.random() * (4 - box[0].y));
32150 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32151 y : minY + (this.unitWidth + this.gutter) * rand
32158 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32162 if(box[0].size == 'xs'){
32165 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32170 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32171 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32179 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32184 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32185 y : minY + (this.unitWidth + this.gutter) * 2
32192 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32196 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32199 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32204 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32205 y : minY + (this.unitWidth + this.gutter) * 1
32209 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32210 y : minY + (this.unitWidth + this.gutter) * 2
32217 if(box[0].size == 'xs' && box[1].size == 'xs'){
32220 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32225 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32230 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32231 y : minY + (this.unitWidth + this.gutter) * 1
32239 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32244 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32245 y : minY + (this.unitWidth + this.gutter) * 2
32249 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32250 y : minY + (this.unitWidth + this.gutter) * 2
32257 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32261 if(box[0].size == 'xs'){
32264 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32269 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32274 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),
32279 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32280 y : minY + (this.unitWidth + this.gutter) * 1
32288 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32293 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32294 y : minY + (this.unitWidth + this.gutter) * 2
32298 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32299 y : minY + (this.unitWidth + this.gutter) * 2
32303 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),
32304 y : minY + (this.unitWidth + this.gutter) * 2
32312 * remove a Masonry Brick
32313 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32315 removeBrick : function(brick_id)
32321 for (var i = 0; i<this.bricks.length; i++) {
32322 if (this.bricks[i].id == brick_id) {
32323 this.bricks.splice(i,1);
32324 this.el.dom.removeChild(Roo.get(brick_id).dom);
32331 * adds a Masonry Brick
32332 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32334 addBrick : function(cfg)
32336 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32337 //this.register(cn);
32338 cn.parentId = this.id;
32339 cn.render(this.el);
32344 * register a Masonry Brick
32345 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32348 register : function(brick)
32350 this.bricks.push(brick);
32351 brick.masonryId = this.id;
32355 * clear all the Masonry Brick
32357 clearAll : function()
32360 //this.getChildContainer().dom.innerHTML = "";
32361 this.el.dom.innerHTML = '';
32364 getSelected : function()
32366 if (!this.selectedBrick) {
32370 return this.selectedBrick;
32374 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32378 * register a Masonry Layout
32379 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32382 register : function(layout)
32384 this.groups[layout.id] = layout;
32387 * fetch a Masonry Layout based on the masonry layout ID
32388 * @param {string} the masonry layout to add
32389 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32392 get: function(layout_id) {
32393 if (typeof(this.groups[layout_id]) == 'undefined') {
32396 return this.groups[layout_id] ;
32408 * http://masonry.desandro.com
32410 * The idea is to render all the bricks based on vertical width...
32412 * The original code extends 'outlayer' - we might need to use that....
32418 * @class Roo.bootstrap.LayoutMasonryAuto
32419 * @extends Roo.bootstrap.Component
32420 * Bootstrap Layout Masonry class
32423 * Create a new Element
32424 * @param {Object} config The config object
32427 Roo.bootstrap.LayoutMasonryAuto = function(config){
32428 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32431 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32434 * @cfg {Boolean} isFitWidth - resize the width..
32436 isFitWidth : false, // options..
32438 * @cfg {Boolean} isOriginLeft = left align?
32440 isOriginLeft : true,
32442 * @cfg {Boolean} isOriginTop = top align?
32444 isOriginTop : false,
32446 * @cfg {Boolean} isLayoutInstant = no animation?
32448 isLayoutInstant : false, // needed?
32450 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32452 isResizingContainer : true,
32454 * @cfg {Number} columnWidth width of the columns
32460 * @cfg {Number} maxCols maximum number of columns
32465 * @cfg {Number} padHeight padding below box..
32471 * @cfg {Boolean} isAutoInitial defalut true
32474 isAutoInitial : true,
32480 initialColumnWidth : 0,
32481 currentSize : null,
32483 colYs : null, // array.
32490 bricks: null, //CompositeElement
32491 cols : 0, // array?
32492 // element : null, // wrapped now this.el
32493 _isLayoutInited : null,
32496 getAutoCreate : function(){
32500 cls: 'blog-masonary-wrapper ' + this.cls,
32502 cls : 'mas-boxes masonary'
32509 getChildContainer: function( )
32511 if (this.boxesEl) {
32512 return this.boxesEl;
32515 this.boxesEl = this.el.select('.mas-boxes').first();
32517 return this.boxesEl;
32521 initEvents : function()
32525 if(this.isAutoInitial){
32526 Roo.log('hook children rendered');
32527 this.on('childrenrendered', function() {
32528 Roo.log('children rendered');
32535 initial : function()
32537 this.reloadItems();
32539 this.currentSize = this.el.getBox(true);
32541 /// was window resize... - let's see if this works..
32542 Roo.EventManager.onWindowResize(this.resize, this);
32544 if(!this.isAutoInitial){
32549 this.layout.defer(500,this);
32552 reloadItems: function()
32554 this.bricks = this.el.select('.masonry-brick', true);
32556 this.bricks.each(function(b) {
32557 //Roo.log(b.getSize());
32558 if (!b.attr('originalwidth')) {
32559 b.attr('originalwidth', b.getSize().width);
32564 Roo.log(this.bricks.elements.length);
32567 resize : function()
32570 var cs = this.el.getBox(true);
32572 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32573 Roo.log("no change in with or X");
32576 this.currentSize = cs;
32580 layout : function()
32583 this._resetLayout();
32584 //this._manageStamps();
32586 // don't animate first layout
32587 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32588 this.layoutItems( isInstant );
32590 // flag for initalized
32591 this._isLayoutInited = true;
32594 layoutItems : function( isInstant )
32596 //var items = this._getItemsForLayout( this.items );
32597 // original code supports filtering layout items.. we just ignore it..
32599 this._layoutItems( this.bricks , isInstant );
32601 this._postLayout();
32603 _layoutItems : function ( items , isInstant)
32605 //this.fireEvent( 'layout', this, items );
32608 if ( !items || !items.elements.length ) {
32609 // no items, emit event with empty array
32614 items.each(function(item) {
32615 Roo.log("layout item");
32617 // get x/y object from method
32618 var position = this._getItemLayoutPosition( item );
32620 position.item = item;
32621 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32622 queue.push( position );
32625 this._processLayoutQueue( queue );
32627 /** Sets position of item in DOM
32628 * @param {Element} item
32629 * @param {Number} x - horizontal position
32630 * @param {Number} y - vertical position
32631 * @param {Boolean} isInstant - disables transitions
32633 _processLayoutQueue : function( queue )
32635 for ( var i=0, len = queue.length; i < len; i++ ) {
32636 var obj = queue[i];
32637 obj.item.position('absolute');
32638 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32644 * Any logic you want to do after each layout,
32645 * i.e. size the container
32647 _postLayout : function()
32649 this.resizeContainer();
32652 resizeContainer : function()
32654 if ( !this.isResizingContainer ) {
32657 var size = this._getContainerSize();
32659 this.el.setSize(size.width,size.height);
32660 this.boxesEl.setSize(size.width,size.height);
32666 _resetLayout : function()
32668 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32669 this.colWidth = this.el.getWidth();
32670 //this.gutter = this.el.getWidth();
32672 this.measureColumns();
32678 this.colYs.push( 0 );
32684 measureColumns : function()
32686 this.getContainerWidth();
32687 // if columnWidth is 0, default to outerWidth of first item
32688 if ( !this.columnWidth ) {
32689 var firstItem = this.bricks.first();
32690 Roo.log(firstItem);
32691 this.columnWidth = this.containerWidth;
32692 if (firstItem && firstItem.attr('originalwidth') ) {
32693 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32695 // columnWidth fall back to item of first element
32696 Roo.log("set column width?");
32697 this.initialColumnWidth = this.columnWidth ;
32699 // if first elem has no width, default to size of container
32704 if (this.initialColumnWidth) {
32705 this.columnWidth = this.initialColumnWidth;
32710 // column width is fixed at the top - however if container width get's smaller we should
32713 // this bit calcs how man columns..
32715 var columnWidth = this.columnWidth += this.gutter;
32717 // calculate columns
32718 var containerWidth = this.containerWidth + this.gutter;
32720 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32721 // fix rounding errors, typically with gutters
32722 var excess = columnWidth - containerWidth % columnWidth;
32725 // if overshoot is less than a pixel, round up, otherwise floor it
32726 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32727 cols = Math[ mathMethod ]( cols );
32728 this.cols = Math.max( cols, 1 );
32729 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32731 // padding positioning..
32732 var totalColWidth = this.cols * this.columnWidth;
32733 var padavail = this.containerWidth - totalColWidth;
32734 // so for 2 columns - we need 3 'pads'
32736 var padNeeded = (1+this.cols) * this.padWidth;
32738 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32740 this.columnWidth += padExtra
32741 //this.padWidth = Math.floor(padavail / ( this.cols));
32743 // adjust colum width so that padding is fixed??
32745 // we have 3 columns ... total = width * 3
32746 // we have X left over... that should be used by
32748 //if (this.expandC) {
32756 getContainerWidth : function()
32758 /* // container is parent if fit width
32759 var container = this.isFitWidth ? this.element.parentNode : this.element;
32760 // check that this.size and size are there
32761 // IE8 triggers resize on body size change, so they might not be
32763 var size = getSize( container ); //FIXME
32764 this.containerWidth = size && size.innerWidth; //FIXME
32767 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32771 _getItemLayoutPosition : function( item ) // what is item?
32773 // we resize the item to our columnWidth..
32775 item.setWidth(this.columnWidth);
32776 item.autoBoxAdjust = false;
32778 var sz = item.getSize();
32780 // how many columns does this brick span
32781 var remainder = this.containerWidth % this.columnWidth;
32783 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32784 // round if off by 1 pixel, otherwise use ceil
32785 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32786 colSpan = Math.min( colSpan, this.cols );
32788 // normally this should be '1' as we dont' currently allow multi width columns..
32790 var colGroup = this._getColGroup( colSpan );
32791 // get the minimum Y value from the columns
32792 var minimumY = Math.min.apply( Math, colGroup );
32793 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32795 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32797 // position the brick
32799 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32800 y: this.currentSize.y + minimumY + this.padHeight
32804 // apply setHeight to necessary columns
32805 var setHeight = minimumY + sz.height + this.padHeight;
32806 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32808 var setSpan = this.cols + 1 - colGroup.length;
32809 for ( var i = 0; i < setSpan; i++ ) {
32810 this.colYs[ shortColIndex + i ] = setHeight ;
32817 * @param {Number} colSpan - number of columns the element spans
32818 * @returns {Array} colGroup
32820 _getColGroup : function( colSpan )
32822 if ( colSpan < 2 ) {
32823 // if brick spans only one column, use all the column Ys
32828 // how many different places could this brick fit horizontally
32829 var groupCount = this.cols + 1 - colSpan;
32830 // for each group potential horizontal position
32831 for ( var i = 0; i < groupCount; i++ ) {
32832 // make an array of colY values for that one group
32833 var groupColYs = this.colYs.slice( i, i + colSpan );
32834 // and get the max value of the array
32835 colGroup[i] = Math.max.apply( Math, groupColYs );
32840 _manageStamp : function( stamp )
32842 var stampSize = stamp.getSize();
32843 var offset = stamp.getBox();
32844 // get the columns that this stamp affects
32845 var firstX = this.isOriginLeft ? offset.x : offset.right;
32846 var lastX = firstX + stampSize.width;
32847 var firstCol = Math.floor( firstX / this.columnWidth );
32848 firstCol = Math.max( 0, firstCol );
32850 var lastCol = Math.floor( lastX / this.columnWidth );
32851 // lastCol should not go over if multiple of columnWidth #425
32852 lastCol -= lastX % this.columnWidth ? 0 : 1;
32853 lastCol = Math.min( this.cols - 1, lastCol );
32855 // set colYs to bottom of the stamp
32856 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32859 for ( var i = firstCol; i <= lastCol; i++ ) {
32860 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32865 _getContainerSize : function()
32867 this.maxY = Math.max.apply( Math, this.colYs );
32872 if ( this.isFitWidth ) {
32873 size.width = this._getContainerFitWidth();
32879 _getContainerFitWidth : function()
32881 var unusedCols = 0;
32882 // count unused columns
32885 if ( this.colYs[i] !== 0 ) {
32890 // fit container to columns that have been used
32891 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32894 needsResizeLayout : function()
32896 var previousWidth = this.containerWidth;
32897 this.getContainerWidth();
32898 return previousWidth !== this.containerWidth;
32913 * @class Roo.bootstrap.MasonryBrick
32914 * @extends Roo.bootstrap.Component
32915 * Bootstrap MasonryBrick class
32918 * Create a new MasonryBrick
32919 * @param {Object} config The config object
32922 Roo.bootstrap.MasonryBrick = function(config){
32924 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32926 Roo.bootstrap.MasonryBrick.register(this);
32932 * When a MasonryBrick is clcik
32933 * @param {Roo.bootstrap.MasonryBrick} this
32934 * @param {Roo.EventObject} e
32940 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32943 * @cfg {String} title
32947 * @cfg {String} html
32951 * @cfg {String} bgimage
32955 * @cfg {String} videourl
32959 * @cfg {String} cls
32963 * @cfg {String} href
32967 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32972 * @cfg {String} placetitle (center|bottom)
32977 * @cfg {Boolean} isFitContainer defalut true
32979 isFitContainer : true,
32982 * @cfg {Boolean} preventDefault defalut false
32984 preventDefault : false,
32987 * @cfg {Boolean} inverse defalut false
32989 maskInverse : false,
32991 getAutoCreate : function()
32993 if(!this.isFitContainer){
32994 return this.getSplitAutoCreate();
32997 var cls = 'masonry-brick masonry-brick-full';
32999 if(this.href.length){
33000 cls += ' masonry-brick-link';
33003 if(this.bgimage.length){
33004 cls += ' masonry-brick-image';
33007 if(this.maskInverse){
33008 cls += ' mask-inverse';
33011 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33012 cls += ' enable-mask';
33016 cls += ' masonry-' + this.size + '-brick';
33019 if(this.placetitle.length){
33021 switch (this.placetitle) {
33023 cls += ' masonry-center-title';
33026 cls += ' masonry-bottom-title';
33033 if(!this.html.length && !this.bgimage.length){
33034 cls += ' masonry-center-title';
33037 if(!this.html.length && this.bgimage.length){
33038 cls += ' masonry-bottom-title';
33043 cls += ' ' + this.cls;
33047 tag: (this.href.length) ? 'a' : 'div',
33052 cls: 'masonry-brick-mask'
33056 cls: 'masonry-brick-paragraph',
33062 if(this.href.length){
33063 cfg.href = this.href;
33066 var cn = cfg.cn[1].cn;
33068 if(this.title.length){
33071 cls: 'masonry-brick-title',
33076 if(this.html.length){
33079 cls: 'masonry-brick-text',
33084 if (!this.title.length && !this.html.length) {
33085 cfg.cn[1].cls += ' hide';
33088 if(this.bgimage.length){
33091 cls: 'masonry-brick-image-view',
33096 if(this.videourl.length){
33097 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33098 // youtube support only?
33101 cls: 'masonry-brick-image-view',
33104 allowfullscreen : true
33112 getSplitAutoCreate : function()
33114 var cls = 'masonry-brick masonry-brick-split';
33116 if(this.href.length){
33117 cls += ' masonry-brick-link';
33120 if(this.bgimage.length){
33121 cls += ' masonry-brick-image';
33125 cls += ' masonry-' + this.size + '-brick';
33128 switch (this.placetitle) {
33130 cls += ' masonry-center-title';
33133 cls += ' masonry-bottom-title';
33136 if(!this.bgimage.length){
33137 cls += ' masonry-center-title';
33140 if(this.bgimage.length){
33141 cls += ' masonry-bottom-title';
33147 cls += ' ' + this.cls;
33151 tag: (this.href.length) ? 'a' : 'div',
33156 cls: 'masonry-brick-split-head',
33160 cls: 'masonry-brick-paragraph',
33167 cls: 'masonry-brick-split-body',
33173 if(this.href.length){
33174 cfg.href = this.href;
33177 if(this.title.length){
33178 cfg.cn[0].cn[0].cn.push({
33180 cls: 'masonry-brick-title',
33185 if(this.html.length){
33186 cfg.cn[1].cn.push({
33188 cls: 'masonry-brick-text',
33193 if(this.bgimage.length){
33194 cfg.cn[0].cn.push({
33196 cls: 'masonry-brick-image-view',
33201 if(this.videourl.length){
33202 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33203 // youtube support only?
33204 cfg.cn[0].cn.cn.push({
33206 cls: 'masonry-brick-image-view',
33209 allowfullscreen : true
33216 initEvents: function()
33218 switch (this.size) {
33251 this.el.on('touchstart', this.onTouchStart, this);
33252 this.el.on('touchmove', this.onTouchMove, this);
33253 this.el.on('touchend', this.onTouchEnd, this);
33254 this.el.on('contextmenu', this.onContextMenu, this);
33256 this.el.on('mouseenter' ,this.enter, this);
33257 this.el.on('mouseleave', this.leave, this);
33258 this.el.on('click', this.onClick, this);
33261 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33262 this.parent().bricks.push(this);
33267 onClick: function(e, el)
33269 var time = this.endTimer - this.startTimer;
33270 // Roo.log(e.preventDefault());
33273 e.preventDefault();
33278 if(!this.preventDefault){
33282 e.preventDefault();
33284 if (this.activeClass != '') {
33285 this.selectBrick();
33288 this.fireEvent('click', this, e);
33291 enter: function(e, el)
33293 e.preventDefault();
33295 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33299 if(this.bgimage.length && this.html.length){
33300 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33304 leave: function(e, el)
33306 e.preventDefault();
33308 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33312 if(this.bgimage.length && this.html.length){
33313 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33317 onTouchStart: function(e, el)
33319 // e.preventDefault();
33321 this.touchmoved = false;
33323 if(!this.isFitContainer){
33327 if(!this.bgimage.length || !this.html.length){
33331 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33333 this.timer = new Date().getTime();
33337 onTouchMove: function(e, el)
33339 this.touchmoved = true;
33342 onContextMenu : function(e,el)
33344 e.preventDefault();
33345 e.stopPropagation();
33349 onTouchEnd: function(e, el)
33351 // e.preventDefault();
33353 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33360 if(!this.bgimage.length || !this.html.length){
33362 if(this.href.length){
33363 window.location.href = this.href;
33369 if(!this.isFitContainer){
33373 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33375 window.location.href = this.href;
33378 //selection on single brick only
33379 selectBrick : function() {
33381 if (!this.parentId) {
33385 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33386 var index = m.selectedBrick.indexOf(this.id);
33389 m.selectedBrick.splice(index,1);
33390 this.el.removeClass(this.activeClass);
33394 for(var i = 0; i < m.selectedBrick.length; i++) {
33395 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33396 b.el.removeClass(b.activeClass);
33399 m.selectedBrick = [];
33401 m.selectedBrick.push(this.id);
33402 this.el.addClass(this.activeClass);
33406 isSelected : function(){
33407 return this.el.hasClass(this.activeClass);
33412 Roo.apply(Roo.bootstrap.MasonryBrick, {
33415 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33417 * register a Masonry Brick
33418 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33421 register : function(brick)
33423 //this.groups[brick.id] = brick;
33424 this.groups.add(brick.id, brick);
33427 * fetch a masonry brick based on the masonry brick ID
33428 * @param {string} the masonry brick to add
33429 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33432 get: function(brick_id)
33434 // if (typeof(this.groups[brick_id]) == 'undefined') {
33437 // return this.groups[brick_id] ;
33439 if(this.groups.key(brick_id)) {
33440 return this.groups.key(brick_id);
33458 * @class Roo.bootstrap.Brick
33459 * @extends Roo.bootstrap.Component
33460 * Bootstrap Brick class
33463 * Create a new Brick
33464 * @param {Object} config The config object
33467 Roo.bootstrap.Brick = function(config){
33468 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33474 * When a Brick is click
33475 * @param {Roo.bootstrap.Brick} this
33476 * @param {Roo.EventObject} e
33482 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33485 * @cfg {String} title
33489 * @cfg {String} html
33493 * @cfg {String} bgimage
33497 * @cfg {String} cls
33501 * @cfg {String} href
33505 * @cfg {String} video
33509 * @cfg {Boolean} square
33513 getAutoCreate : function()
33515 var cls = 'roo-brick';
33517 if(this.href.length){
33518 cls += ' roo-brick-link';
33521 if(this.bgimage.length){
33522 cls += ' roo-brick-image';
33525 if(!this.html.length && !this.bgimage.length){
33526 cls += ' roo-brick-center-title';
33529 if(!this.html.length && this.bgimage.length){
33530 cls += ' roo-brick-bottom-title';
33534 cls += ' ' + this.cls;
33538 tag: (this.href.length) ? 'a' : 'div',
33543 cls: 'roo-brick-paragraph',
33549 if(this.href.length){
33550 cfg.href = this.href;
33553 var cn = cfg.cn[0].cn;
33555 if(this.title.length){
33558 cls: 'roo-brick-title',
33563 if(this.html.length){
33566 cls: 'roo-brick-text',
33573 if(this.bgimage.length){
33576 cls: 'roo-brick-image-view',
33584 initEvents: function()
33586 if(this.title.length || this.html.length){
33587 this.el.on('mouseenter' ,this.enter, this);
33588 this.el.on('mouseleave', this.leave, this);
33591 Roo.EventManager.onWindowResize(this.resize, this);
33593 if(this.bgimage.length){
33594 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33595 this.imageEl.on('load', this.onImageLoad, this);
33602 onImageLoad : function()
33607 resize : function()
33609 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33611 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33613 if(this.bgimage.length){
33614 var image = this.el.select('.roo-brick-image-view', true).first();
33616 image.setWidth(paragraph.getWidth());
33619 image.setHeight(paragraph.getWidth());
33622 this.el.setHeight(image.getHeight());
33623 paragraph.setHeight(image.getHeight());
33629 enter: function(e, el)
33631 e.preventDefault();
33633 if(this.bgimage.length){
33634 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33635 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33639 leave: function(e, el)
33641 e.preventDefault();
33643 if(this.bgimage.length){
33644 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33645 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33660 * @class Roo.bootstrap.NumberField
33661 * @extends Roo.bootstrap.Input
33662 * Bootstrap NumberField class
33668 * Create a new NumberField
33669 * @param {Object} config The config object
33672 Roo.bootstrap.NumberField = function(config){
33673 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33676 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33679 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33681 allowDecimals : true,
33683 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33685 decimalSeparator : ".",
33687 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33689 decimalPrecision : 2,
33691 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33693 allowNegative : true,
33696 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33700 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33702 minValue : Number.NEGATIVE_INFINITY,
33704 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33706 maxValue : Number.MAX_VALUE,
33708 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33710 minText : "The minimum value for this field is {0}",
33712 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33714 maxText : "The maximum value for this field is {0}",
33716 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33717 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33719 nanText : "{0} is not a valid number",
33721 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33723 thousandsDelimiter : false,
33725 * @cfg {String} valueAlign alignment of value
33727 valueAlign : "left",
33729 getAutoCreate : function()
33731 var hiddenInput = {
33735 cls: 'hidden-number-input'
33739 hiddenInput.name = this.name;
33744 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33746 this.name = hiddenInput.name;
33748 if(cfg.cn.length > 0) {
33749 cfg.cn.push(hiddenInput);
33756 initEvents : function()
33758 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33760 var allowed = "0123456789";
33762 if(this.allowDecimals){
33763 allowed += this.decimalSeparator;
33766 if(this.allowNegative){
33770 if(this.thousandsDelimiter) {
33774 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33776 var keyPress = function(e){
33778 var k = e.getKey();
33780 var c = e.getCharCode();
33783 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33784 allowed.indexOf(String.fromCharCode(c)) === -1
33790 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33794 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33799 this.el.on("keypress", keyPress, this);
33802 validateValue : function(value)
33805 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33809 var num = this.parseValue(value);
33812 this.markInvalid(String.format(this.nanText, value));
33816 if(num < this.minValue){
33817 this.markInvalid(String.format(this.minText, this.minValue));
33821 if(num > this.maxValue){
33822 this.markInvalid(String.format(this.maxText, this.maxValue));
33829 getValue : function()
33831 var v = this.hiddenEl().getValue();
33833 return this.fixPrecision(this.parseValue(v));
33836 parseValue : function(value)
33838 if(this.thousandsDelimiter) {
33840 r = new RegExp(",", "g");
33841 value = value.replace(r, "");
33844 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33845 return isNaN(value) ? '' : value;
33848 fixPrecision : function(value)
33850 if(this.thousandsDelimiter) {
33852 r = new RegExp(",", "g");
33853 value = value.replace(r, "");
33856 var nan = isNaN(value);
33858 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33859 return nan ? '' : value;
33861 return parseFloat(value).toFixed(this.decimalPrecision);
33864 setValue : function(v)
33866 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33872 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33874 this.inputEl().dom.value = (v == '') ? '' :
33875 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33877 if(!this.allowZero && v === '0') {
33878 this.hiddenEl().dom.value = '';
33879 this.inputEl().dom.value = '';
33886 decimalPrecisionFcn : function(v)
33888 return Math.floor(v);
33891 beforeBlur : function()
33893 var v = this.parseValue(this.getRawValue());
33895 if(v || v === 0 || v === ''){
33900 hiddenEl : function()
33902 return this.el.select('input.hidden-number-input',true).first();
33914 * @class Roo.bootstrap.DocumentSlider
33915 * @extends Roo.bootstrap.Component
33916 * Bootstrap DocumentSlider class
33919 * Create a new DocumentViewer
33920 * @param {Object} config The config object
33923 Roo.bootstrap.DocumentSlider = function(config){
33924 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33931 * Fire after initEvent
33932 * @param {Roo.bootstrap.DocumentSlider} this
33937 * Fire after update
33938 * @param {Roo.bootstrap.DocumentSlider} this
33944 * @param {Roo.bootstrap.DocumentSlider} this
33950 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33956 getAutoCreate : function()
33960 cls : 'roo-document-slider',
33964 cls : 'roo-document-slider-header',
33968 cls : 'roo-document-slider-header-title'
33974 cls : 'roo-document-slider-body',
33978 cls : 'roo-document-slider-prev',
33982 cls : 'fa fa-chevron-left'
33988 cls : 'roo-document-slider-thumb',
33992 cls : 'roo-document-slider-image'
33998 cls : 'roo-document-slider-next',
34002 cls : 'fa fa-chevron-right'
34014 initEvents : function()
34016 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34017 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34019 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34020 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34022 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34023 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34025 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34026 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34028 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34029 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34031 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34032 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34034 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34035 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34037 this.thumbEl.on('click', this.onClick, this);
34039 this.prevIndicator.on('click', this.prev, this);
34041 this.nextIndicator.on('click', this.next, this);
34045 initial : function()
34047 if(this.files.length){
34048 this.indicator = 1;
34052 this.fireEvent('initial', this);
34055 update : function()
34057 this.imageEl.attr('src', this.files[this.indicator - 1]);
34059 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34061 this.prevIndicator.show();
34063 if(this.indicator == 1){
34064 this.prevIndicator.hide();
34067 this.nextIndicator.show();
34069 if(this.indicator == this.files.length){
34070 this.nextIndicator.hide();
34073 this.thumbEl.scrollTo('top');
34075 this.fireEvent('update', this);
34078 onClick : function(e)
34080 e.preventDefault();
34082 this.fireEvent('click', this);
34087 e.preventDefault();
34089 this.indicator = Math.max(1, this.indicator - 1);
34096 e.preventDefault();
34098 this.indicator = Math.min(this.files.length, this.indicator + 1);
34112 * @class Roo.bootstrap.RadioSet
34113 * @extends Roo.bootstrap.Input
34114 * Bootstrap RadioSet class
34115 * @cfg {String} indicatorpos (left|right) default left
34116 * @cfg {Boolean} inline (true|false) inline the element (default true)
34117 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34119 * Create a new RadioSet
34120 * @param {Object} config The config object
34123 Roo.bootstrap.RadioSet = function(config){
34125 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34129 Roo.bootstrap.RadioSet.register(this);
34134 * Fires when the element is checked or unchecked.
34135 * @param {Roo.bootstrap.RadioSet} this This radio
34136 * @param {Roo.bootstrap.Radio} item The checked item
34141 * Fires when the element is click.
34142 * @param {Roo.bootstrap.RadioSet} this This radio set
34143 * @param {Roo.bootstrap.Radio} item The checked item
34144 * @param {Roo.EventObject} e The event object
34151 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34159 indicatorpos : 'left',
34161 getAutoCreate : function()
34165 cls : 'roo-radio-set-label',
34169 html : this.fieldLabel
34173 if (Roo.bootstrap.version == 3) {
34176 if(this.indicatorpos == 'left'){
34179 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34180 tooltip : 'This field is required'
34185 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34186 tooltip : 'This field is required'
34192 cls : 'roo-radio-set-items'
34195 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34197 if (align === 'left' && this.fieldLabel.length) {
34200 cls : "roo-radio-set-right",
34206 if(this.labelWidth > 12){
34207 label.style = "width: " + this.labelWidth + 'px';
34210 if(this.labelWidth < 13 && this.labelmd == 0){
34211 this.labelmd = this.labelWidth;
34214 if(this.labellg > 0){
34215 label.cls += ' col-lg-' + this.labellg;
34216 items.cls += ' col-lg-' + (12 - this.labellg);
34219 if(this.labelmd > 0){
34220 label.cls += ' col-md-' + this.labelmd;
34221 items.cls += ' col-md-' + (12 - this.labelmd);
34224 if(this.labelsm > 0){
34225 label.cls += ' col-sm-' + this.labelsm;
34226 items.cls += ' col-sm-' + (12 - this.labelsm);
34229 if(this.labelxs > 0){
34230 label.cls += ' col-xs-' + this.labelxs;
34231 items.cls += ' col-xs-' + (12 - this.labelxs);
34237 cls : 'roo-radio-set',
34241 cls : 'roo-radio-set-input',
34244 value : this.value ? this.value : ''
34251 if(this.weight.length){
34252 cfg.cls += ' roo-radio-' + this.weight;
34256 cfg.cls += ' roo-radio-set-inline';
34260 ['xs','sm','md','lg'].map(function(size){
34261 if (settings[size]) {
34262 cfg.cls += ' col-' + size + '-' + settings[size];
34270 initEvents : function()
34272 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34273 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34275 if(!this.fieldLabel.length){
34276 this.labelEl.hide();
34279 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34280 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34282 this.indicator = this.indicatorEl();
34284 if(this.indicator){
34285 this.indicator.addClass('invisible');
34288 this.originalValue = this.getValue();
34292 inputEl: function ()
34294 return this.el.select('.roo-radio-set-input', true).first();
34297 getChildContainer : function()
34299 return this.itemsEl;
34302 register : function(item)
34304 this.radioes.push(item);
34308 validate : function()
34310 if(this.getVisibilityEl().hasClass('hidden')){
34316 Roo.each(this.radioes, function(i){
34325 if(this.allowBlank) {
34329 if(this.disabled || valid){
34334 this.markInvalid();
34339 markValid : function()
34341 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34342 this.indicatorEl().removeClass('visible');
34343 this.indicatorEl().addClass('invisible');
34347 if (Roo.bootstrap.version == 3) {
34348 this.el.removeClass([this.invalidClass, this.validClass]);
34349 this.el.addClass(this.validClass);
34351 this.el.removeClass(['is-invalid','is-valid']);
34352 this.el.addClass(['is-valid']);
34354 this.fireEvent('valid', this);
34357 markInvalid : function(msg)
34359 if(this.allowBlank || this.disabled){
34363 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34364 this.indicatorEl().removeClass('invisible');
34365 this.indicatorEl().addClass('visible');
34367 if (Roo.bootstrap.version == 3) {
34368 this.el.removeClass([this.invalidClass, this.validClass]);
34369 this.el.addClass(this.invalidClass);
34371 this.el.removeClass(['is-invalid','is-valid']);
34372 this.el.addClass(['is-invalid']);
34375 this.fireEvent('invalid', this, msg);
34379 setValue : function(v, suppressEvent)
34381 if(this.value === v){
34388 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34391 Roo.each(this.radioes, function(i){
34393 i.el.removeClass('checked');
34396 Roo.each(this.radioes, function(i){
34398 if(i.value === v || i.value.toString() === v.toString()){
34400 i.el.addClass('checked');
34402 if(suppressEvent !== true){
34403 this.fireEvent('check', this, i);
34414 clearInvalid : function(){
34416 if(!this.el || this.preventMark){
34420 this.el.removeClass([this.invalidClass]);
34422 this.fireEvent('valid', this);
34427 Roo.apply(Roo.bootstrap.RadioSet, {
34431 register : function(set)
34433 this.groups[set.name] = set;
34436 get: function(name)
34438 if (typeof(this.groups[name]) == 'undefined') {
34442 return this.groups[name] ;
34448 * Ext JS Library 1.1.1
34449 * Copyright(c) 2006-2007, Ext JS, LLC.
34451 * Originally Released Under LGPL - original licence link has changed is not relivant.
34454 * <script type="text/javascript">
34459 * @class Roo.bootstrap.SplitBar
34460 * @extends Roo.util.Observable
34461 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34465 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34466 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34467 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34468 split.minSize = 100;
34469 split.maxSize = 600;
34470 split.animate = true;
34471 split.on('moved', splitterMoved);
34474 * Create a new SplitBar
34475 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34476 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34477 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34478 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34479 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34480 position of the SplitBar).
34482 Roo.bootstrap.SplitBar = function(cfg){
34487 // dragElement : elm
34488 // resizingElement: el,
34490 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34491 // placement : Roo.bootstrap.SplitBar.LEFT ,
34492 // existingProxy ???
34495 this.el = Roo.get(cfg.dragElement, true);
34496 this.el.dom.unselectable = "on";
34498 this.resizingEl = Roo.get(cfg.resizingElement, true);
34502 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34503 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34506 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34509 * The minimum size of the resizing element. (Defaults to 0)
34515 * The maximum size of the resizing element. (Defaults to 2000)
34518 this.maxSize = 2000;
34521 * Whether to animate the transition to the new size
34524 this.animate = false;
34527 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34530 this.useShim = false;
34535 if(!cfg.existingProxy){
34537 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34539 this.proxy = Roo.get(cfg.existingProxy).dom;
34542 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34545 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34548 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34551 this.dragSpecs = {};
34554 * @private The adapter to use to positon and resize elements
34556 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34557 this.adapter.init(this);
34559 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34561 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34562 this.el.addClass("roo-splitbar-h");
34565 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34566 this.el.addClass("roo-splitbar-v");
34572 * Fires when the splitter is moved (alias for {@link #event-moved})
34573 * @param {Roo.bootstrap.SplitBar} this
34574 * @param {Number} newSize the new width or height
34579 * Fires when the splitter is moved
34580 * @param {Roo.bootstrap.SplitBar} this
34581 * @param {Number} newSize the new width or height
34585 * @event beforeresize
34586 * Fires before the splitter is dragged
34587 * @param {Roo.bootstrap.SplitBar} this
34589 "beforeresize" : true,
34591 "beforeapply" : true
34594 Roo.util.Observable.call(this);
34597 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34598 onStartProxyDrag : function(x, y){
34599 this.fireEvent("beforeresize", this);
34601 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34603 o.enableDisplayMode("block");
34604 // all splitbars share the same overlay
34605 Roo.bootstrap.SplitBar.prototype.overlay = o;
34607 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34608 this.overlay.show();
34609 Roo.get(this.proxy).setDisplayed("block");
34610 var size = this.adapter.getElementSize(this);
34611 this.activeMinSize = this.getMinimumSize();;
34612 this.activeMaxSize = this.getMaximumSize();;
34613 var c1 = size - this.activeMinSize;
34614 var c2 = Math.max(this.activeMaxSize - size, 0);
34615 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34616 this.dd.resetConstraints();
34617 this.dd.setXConstraint(
34618 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34619 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34621 this.dd.setYConstraint(0, 0);
34623 this.dd.resetConstraints();
34624 this.dd.setXConstraint(0, 0);
34625 this.dd.setYConstraint(
34626 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34627 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34630 this.dragSpecs.startSize = size;
34631 this.dragSpecs.startPoint = [x, y];
34632 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34636 * @private Called after the drag operation by the DDProxy
34638 onEndProxyDrag : function(e){
34639 Roo.get(this.proxy).setDisplayed(false);
34640 var endPoint = Roo.lib.Event.getXY(e);
34642 this.overlay.hide();
34645 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34646 newSize = this.dragSpecs.startSize +
34647 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34648 endPoint[0] - this.dragSpecs.startPoint[0] :
34649 this.dragSpecs.startPoint[0] - endPoint[0]
34652 newSize = this.dragSpecs.startSize +
34653 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34654 endPoint[1] - this.dragSpecs.startPoint[1] :
34655 this.dragSpecs.startPoint[1] - endPoint[1]
34658 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34659 if(newSize != this.dragSpecs.startSize){
34660 if(this.fireEvent('beforeapply', this, newSize) !== false){
34661 this.adapter.setElementSize(this, newSize);
34662 this.fireEvent("moved", this, newSize);
34663 this.fireEvent("resize", this, newSize);
34669 * Get the adapter this SplitBar uses
34670 * @return The adapter object
34672 getAdapter : function(){
34673 return this.adapter;
34677 * Set the adapter this SplitBar uses
34678 * @param {Object} adapter A SplitBar adapter object
34680 setAdapter : function(adapter){
34681 this.adapter = adapter;
34682 this.adapter.init(this);
34686 * Gets the minimum size for the resizing element
34687 * @return {Number} The minimum size
34689 getMinimumSize : function(){
34690 return this.minSize;
34694 * Sets the minimum size for the resizing element
34695 * @param {Number} minSize The minimum size
34697 setMinimumSize : function(minSize){
34698 this.minSize = minSize;
34702 * Gets the maximum size for the resizing element
34703 * @return {Number} The maximum size
34705 getMaximumSize : function(){
34706 return this.maxSize;
34710 * Sets the maximum size for the resizing element
34711 * @param {Number} maxSize The maximum size
34713 setMaximumSize : function(maxSize){
34714 this.maxSize = maxSize;
34718 * Sets the initialize size for the resizing element
34719 * @param {Number} size The initial size
34721 setCurrentSize : function(size){
34722 var oldAnimate = this.animate;
34723 this.animate = false;
34724 this.adapter.setElementSize(this, size);
34725 this.animate = oldAnimate;
34729 * Destroy this splitbar.
34730 * @param {Boolean} removeEl True to remove the element
34732 destroy : function(removeEl){
34734 this.shim.remove();
34737 this.proxy.parentNode.removeChild(this.proxy);
34745 * @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.
34747 Roo.bootstrap.SplitBar.createProxy = function(dir){
34748 var proxy = new Roo.Element(document.createElement("div"));
34749 proxy.unselectable();
34750 var cls = 'roo-splitbar-proxy';
34751 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34752 document.body.appendChild(proxy.dom);
34757 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34758 * Default Adapter. It assumes the splitter and resizing element are not positioned
34759 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34761 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34764 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34765 // do nothing for now
34766 init : function(s){
34770 * Called before drag operations to get the current size of the resizing element.
34771 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34773 getElementSize : function(s){
34774 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34775 return s.resizingEl.getWidth();
34777 return s.resizingEl.getHeight();
34782 * Called after drag operations to set the size of the resizing element.
34783 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34784 * @param {Number} newSize The new size to set
34785 * @param {Function} onComplete A function to be invoked when resizing is complete
34787 setElementSize : function(s, newSize, onComplete){
34788 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34790 s.resizingEl.setWidth(newSize);
34792 onComplete(s, newSize);
34795 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34800 s.resizingEl.setHeight(newSize);
34802 onComplete(s, newSize);
34805 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34812 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34813 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34814 * Adapter that moves the splitter element to align with the resized sizing element.
34815 * Used with an absolute positioned SplitBar.
34816 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34817 * document.body, make sure you assign an id to the body element.
34819 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34820 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34821 this.container = Roo.get(container);
34824 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34825 init : function(s){
34826 this.basic.init(s);
34829 getElementSize : function(s){
34830 return this.basic.getElementSize(s);
34833 setElementSize : function(s, newSize, onComplete){
34834 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34837 moveSplitter : function(s){
34838 var yes = Roo.bootstrap.SplitBar;
34839 switch(s.placement){
34841 s.el.setX(s.resizingEl.getRight());
34844 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34847 s.el.setY(s.resizingEl.getBottom());
34850 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34857 * Orientation constant - Create a vertical SplitBar
34861 Roo.bootstrap.SplitBar.VERTICAL = 1;
34864 * Orientation constant - Create a horizontal SplitBar
34868 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34871 * Placement constant - The resizing element is to the left of the splitter element
34875 Roo.bootstrap.SplitBar.LEFT = 1;
34878 * Placement constant - The resizing element is to the right of the splitter element
34882 Roo.bootstrap.SplitBar.RIGHT = 2;
34885 * Placement constant - The resizing element is positioned above the splitter element
34889 Roo.bootstrap.SplitBar.TOP = 3;
34892 * Placement constant - The resizing element is positioned under splitter element
34896 Roo.bootstrap.SplitBar.BOTTOM = 4;
34897 Roo.namespace("Roo.bootstrap.layout");/*
34899 * Ext JS Library 1.1.1
34900 * Copyright(c) 2006-2007, Ext JS, LLC.
34902 * Originally Released Under LGPL - original licence link has changed is not relivant.
34905 * <script type="text/javascript">
34909 * @class Roo.bootstrap.layout.Manager
34910 * @extends Roo.bootstrap.Component
34911 * Base class for layout managers.
34913 Roo.bootstrap.layout.Manager = function(config)
34915 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34921 /** false to disable window resize monitoring @type Boolean */
34922 this.monitorWindowResize = true;
34927 * Fires when a layout is performed.
34928 * @param {Roo.LayoutManager} this
34932 * @event regionresized
34933 * Fires when the user resizes a region.
34934 * @param {Roo.LayoutRegion} region The resized region
34935 * @param {Number} newSize The new size (width for east/west, height for north/south)
34937 "regionresized" : true,
34939 * @event regioncollapsed
34940 * Fires when a region is collapsed.
34941 * @param {Roo.LayoutRegion} region The collapsed region
34943 "regioncollapsed" : true,
34945 * @event regionexpanded
34946 * Fires when a region is expanded.
34947 * @param {Roo.LayoutRegion} region The expanded region
34949 "regionexpanded" : true
34951 this.updating = false;
34954 this.el = Roo.get(config.el);
34960 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34965 monitorWindowResize : true,
34971 onRender : function(ct, position)
34974 this.el = Roo.get(ct);
34977 //this.fireEvent('render',this);
34981 initEvents: function()
34985 // ie scrollbar fix
34986 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34987 document.body.scroll = "no";
34988 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34989 this.el.position('relative');
34991 this.id = this.el.id;
34992 this.el.addClass("roo-layout-container");
34993 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34994 if(this.el.dom != document.body ) {
34995 this.el.on('resize', this.layout,this);
34996 this.el.on('show', this.layout,this);
35002 * Returns true if this layout is currently being updated
35003 * @return {Boolean}
35005 isUpdating : function(){
35006 return this.updating;
35010 * Suspend the LayoutManager from doing auto-layouts while
35011 * making multiple add or remove calls
35013 beginUpdate : function(){
35014 this.updating = true;
35018 * Restore auto-layouts and optionally disable the manager from performing a layout
35019 * @param {Boolean} noLayout true to disable a layout update
35021 endUpdate : function(noLayout){
35022 this.updating = false;
35028 layout: function(){
35032 onRegionResized : function(region, newSize){
35033 this.fireEvent("regionresized", region, newSize);
35037 onRegionCollapsed : function(region){
35038 this.fireEvent("regioncollapsed", region);
35041 onRegionExpanded : function(region){
35042 this.fireEvent("regionexpanded", region);
35046 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35047 * performs box-model adjustments.
35048 * @return {Object} The size as an object {width: (the width), height: (the height)}
35050 getViewSize : function()
35053 if(this.el.dom != document.body){
35054 size = this.el.getSize();
35056 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35058 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35059 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35064 * Returns the Element this layout is bound to.
35065 * @return {Roo.Element}
35067 getEl : function(){
35072 * Returns the specified region.
35073 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35074 * @return {Roo.LayoutRegion}
35076 getRegion : function(target){
35077 return this.regions[target.toLowerCase()];
35080 onWindowResize : function(){
35081 if(this.monitorWindowResize){
35088 * Ext JS Library 1.1.1
35089 * Copyright(c) 2006-2007, Ext JS, LLC.
35091 * Originally Released Under LGPL - original licence link has changed is not relivant.
35094 * <script type="text/javascript">
35097 * @class Roo.bootstrap.layout.Border
35098 * @extends Roo.bootstrap.layout.Manager
35099 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35100 * please see: examples/bootstrap/nested.html<br><br>
35102 <b>The container the layout is rendered into can be either the body element or any other element.
35103 If it is not the body element, the container needs to either be an absolute positioned element,
35104 or you will need to add "position:relative" to the css of the container. You will also need to specify
35105 the container size if it is not the body element.</b>
35108 * Create a new Border
35109 * @param {Object} config Configuration options
35111 Roo.bootstrap.layout.Border = function(config){
35112 config = config || {};
35113 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35117 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35118 if(config[region]){
35119 config[region].region = region;
35120 this.addRegion(config[region]);
35126 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35128 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35130 parent : false, // this might point to a 'nest' or a ???
35133 * Creates and adds a new region if it doesn't already exist.
35134 * @param {String} target The target region key (north, south, east, west or center).
35135 * @param {Object} config The regions config object
35136 * @return {BorderLayoutRegion} The new region
35138 addRegion : function(config)
35140 if(!this.regions[config.region]){
35141 var r = this.factory(config);
35142 this.bindRegion(r);
35144 return this.regions[config.region];
35148 bindRegion : function(r){
35149 this.regions[r.config.region] = r;
35151 r.on("visibilitychange", this.layout, this);
35152 r.on("paneladded", this.layout, this);
35153 r.on("panelremoved", this.layout, this);
35154 r.on("invalidated", this.layout, this);
35155 r.on("resized", this.onRegionResized, this);
35156 r.on("collapsed", this.onRegionCollapsed, this);
35157 r.on("expanded", this.onRegionExpanded, this);
35161 * Performs a layout update.
35163 layout : function()
35165 if(this.updating) {
35169 // render all the rebions if they have not been done alreayd?
35170 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35171 if(this.regions[region] && !this.regions[region].bodyEl){
35172 this.regions[region].onRender(this.el)
35176 var size = this.getViewSize();
35177 var w = size.width;
35178 var h = size.height;
35183 //var x = 0, y = 0;
35185 var rs = this.regions;
35186 var north = rs["north"];
35187 var south = rs["south"];
35188 var west = rs["west"];
35189 var east = rs["east"];
35190 var center = rs["center"];
35191 //if(this.hideOnLayout){ // not supported anymore
35192 //c.el.setStyle("display", "none");
35194 if(north && north.isVisible()){
35195 var b = north.getBox();
35196 var m = north.getMargins();
35197 b.width = w - (m.left+m.right);
35200 centerY = b.height + b.y + m.bottom;
35201 centerH -= centerY;
35202 north.updateBox(this.safeBox(b));
35204 if(south && south.isVisible()){
35205 var b = south.getBox();
35206 var m = south.getMargins();
35207 b.width = w - (m.left+m.right);
35209 var totalHeight = (b.height + m.top + m.bottom);
35210 b.y = h - totalHeight + m.top;
35211 centerH -= totalHeight;
35212 south.updateBox(this.safeBox(b));
35214 if(west && west.isVisible()){
35215 var b = west.getBox();
35216 var m = west.getMargins();
35217 b.height = centerH - (m.top+m.bottom);
35219 b.y = centerY + m.top;
35220 var totalWidth = (b.width + m.left + m.right);
35221 centerX += totalWidth;
35222 centerW -= totalWidth;
35223 west.updateBox(this.safeBox(b));
35225 if(east && east.isVisible()){
35226 var b = east.getBox();
35227 var m = east.getMargins();
35228 b.height = centerH - (m.top+m.bottom);
35229 var totalWidth = (b.width + m.left + m.right);
35230 b.x = w - totalWidth + m.left;
35231 b.y = centerY + m.top;
35232 centerW -= totalWidth;
35233 east.updateBox(this.safeBox(b));
35236 var m = center.getMargins();
35238 x: centerX + m.left,
35239 y: centerY + m.top,
35240 width: centerW - (m.left+m.right),
35241 height: centerH - (m.top+m.bottom)
35243 //if(this.hideOnLayout){
35244 //center.el.setStyle("display", "block");
35246 center.updateBox(this.safeBox(centerBox));
35249 this.fireEvent("layout", this);
35253 safeBox : function(box){
35254 box.width = Math.max(0, box.width);
35255 box.height = Math.max(0, box.height);
35260 * Adds a ContentPanel (or subclass) to this layout.
35261 * @param {String} target The target region key (north, south, east, west or center).
35262 * @param {Roo.ContentPanel} panel The panel to add
35263 * @return {Roo.ContentPanel} The added panel
35265 add : function(target, panel){
35267 target = target.toLowerCase();
35268 return this.regions[target].add(panel);
35272 * Remove a ContentPanel (or subclass) to this layout.
35273 * @param {String} target The target region key (north, south, east, west or center).
35274 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35275 * @return {Roo.ContentPanel} The removed panel
35277 remove : function(target, panel){
35278 target = target.toLowerCase();
35279 return this.regions[target].remove(panel);
35283 * Searches all regions for a panel with the specified id
35284 * @param {String} panelId
35285 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35287 findPanel : function(panelId){
35288 var rs = this.regions;
35289 for(var target in rs){
35290 if(typeof rs[target] != "function"){
35291 var p = rs[target].getPanel(panelId);
35301 * Searches all regions for a panel with the specified id and activates (shows) it.
35302 * @param {String/ContentPanel} panelId The panels id or the panel itself
35303 * @return {Roo.ContentPanel} The shown panel or null
35305 showPanel : function(panelId) {
35306 var rs = this.regions;
35307 for(var target in rs){
35308 var r = rs[target];
35309 if(typeof r != "function"){
35310 if(r.hasPanel(panelId)){
35311 return r.showPanel(panelId);
35319 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35320 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35323 restoreState : function(provider){
35325 provider = Roo.state.Manager;
35327 var sm = new Roo.LayoutStateManager();
35328 sm.init(this, provider);
35334 * Adds a xtype elements to the layout.
35338 xtype : 'ContentPanel',
35345 xtype : 'NestedLayoutPanel',
35351 items : [ ... list of content panels or nested layout panels.. ]
35355 * @param {Object} cfg Xtype definition of item to add.
35357 addxtype : function(cfg)
35359 // basically accepts a pannel...
35360 // can accept a layout region..!?!?
35361 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35364 // theory? children can only be panels??
35366 //if (!cfg.xtype.match(/Panel$/)) {
35371 if (typeof(cfg.region) == 'undefined') {
35372 Roo.log("Failed to add Panel, region was not set");
35376 var region = cfg.region;
35382 xitems = cfg.items;
35387 if ( region == 'center') {
35388 Roo.log("Center: " + cfg.title);
35394 case 'Content': // ContentPanel (el, cfg)
35395 case 'Scroll': // ContentPanel (el, cfg)
35397 cfg.autoCreate = cfg.autoCreate || true;
35398 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35400 // var el = this.el.createChild();
35401 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35404 this.add(region, ret);
35408 case 'TreePanel': // our new panel!
35409 cfg.el = this.el.createChild();
35410 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35411 this.add(region, ret);
35416 // create a new Layout (which is a Border Layout...
35418 var clayout = cfg.layout;
35419 clayout.el = this.el.createChild();
35420 clayout.items = clayout.items || [];
35424 // replace this exitems with the clayout ones..
35425 xitems = clayout.items;
35427 // force background off if it's in center...
35428 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35429 cfg.background = false;
35431 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35434 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35435 //console.log('adding nested layout panel ' + cfg.toSource());
35436 this.add(region, ret);
35437 nb = {}; /// find first...
35442 // needs grid and region
35444 //var el = this.getRegion(region).el.createChild();
35446 *var el = this.el.createChild();
35447 // create the grid first...
35448 cfg.grid.container = el;
35449 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35452 if (region == 'center' && this.active ) {
35453 cfg.background = false;
35456 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35458 this.add(region, ret);
35460 if (cfg.background) {
35461 // render grid on panel activation (if panel background)
35462 ret.on('activate', function(gp) {
35463 if (!gp.grid.rendered) {
35464 // gp.grid.render(el);
35468 // cfg.grid.render(el);
35474 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35475 // it was the old xcomponent building that caused this before.
35476 // espeically if border is the top element in the tree.
35486 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35488 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35489 this.add(region, ret);
35493 throw "Can not add '" + cfg.xtype + "' to Border";
35499 this.beginUpdate();
35503 Roo.each(xitems, function(i) {
35504 region = nb && i.region ? i.region : false;
35506 var add = ret.addxtype(i);
35509 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35510 if (!i.background) {
35511 abn[region] = nb[region] ;
35518 // make the last non-background panel active..
35519 //if (nb) { Roo.log(abn); }
35522 for(var r in abn) {
35523 region = this.getRegion(r);
35525 // tried using nb[r], but it does not work..
35527 region.showPanel(abn[r]);
35538 factory : function(cfg)
35541 var validRegions = Roo.bootstrap.layout.Border.regions;
35543 var target = cfg.region;
35546 var r = Roo.bootstrap.layout;
35550 return new r.North(cfg);
35552 return new r.South(cfg);
35554 return new r.East(cfg);
35556 return new r.West(cfg);
35558 return new r.Center(cfg);
35560 throw 'Layout region "'+target+'" not supported.';
35567 * Ext JS Library 1.1.1
35568 * Copyright(c) 2006-2007, Ext JS, LLC.
35570 * Originally Released Under LGPL - original licence link has changed is not relivant.
35573 * <script type="text/javascript">
35577 * @class Roo.bootstrap.layout.Basic
35578 * @extends Roo.util.Observable
35579 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35580 * and does not have a titlebar, tabs or any other features. All it does is size and position
35581 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35582 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35583 * @cfg {string} region the region that it inhabits..
35584 * @cfg {bool} skipConfig skip config?
35588 Roo.bootstrap.layout.Basic = function(config){
35590 this.mgr = config.mgr;
35592 this.position = config.region;
35594 var skipConfig = config.skipConfig;
35598 * @scope Roo.BasicLayoutRegion
35602 * @event beforeremove
35603 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35604 * @param {Roo.LayoutRegion} this
35605 * @param {Roo.ContentPanel} panel The panel
35606 * @param {Object} e The cancel event object
35608 "beforeremove" : true,
35610 * @event invalidated
35611 * Fires when the layout for this region is changed.
35612 * @param {Roo.LayoutRegion} this
35614 "invalidated" : true,
35616 * @event visibilitychange
35617 * Fires when this region is shown or hidden
35618 * @param {Roo.LayoutRegion} this
35619 * @param {Boolean} visibility true or false
35621 "visibilitychange" : true,
35623 * @event paneladded
35624 * Fires when a panel is added.
35625 * @param {Roo.LayoutRegion} this
35626 * @param {Roo.ContentPanel} panel The panel
35628 "paneladded" : true,
35630 * @event panelremoved
35631 * Fires when a panel is removed.
35632 * @param {Roo.LayoutRegion} this
35633 * @param {Roo.ContentPanel} panel The panel
35635 "panelremoved" : true,
35637 * @event beforecollapse
35638 * Fires when this region before collapse.
35639 * @param {Roo.LayoutRegion} this
35641 "beforecollapse" : true,
35644 * Fires when this region is collapsed.
35645 * @param {Roo.LayoutRegion} this
35647 "collapsed" : true,
35650 * Fires when this region is expanded.
35651 * @param {Roo.LayoutRegion} this
35656 * Fires when this region is slid into view.
35657 * @param {Roo.LayoutRegion} this
35659 "slideshow" : true,
35662 * Fires when this region slides out of view.
35663 * @param {Roo.LayoutRegion} this
35665 "slidehide" : true,
35667 * @event panelactivated
35668 * Fires when a panel is activated.
35669 * @param {Roo.LayoutRegion} this
35670 * @param {Roo.ContentPanel} panel The activated panel
35672 "panelactivated" : true,
35675 * Fires when the user resizes this region.
35676 * @param {Roo.LayoutRegion} this
35677 * @param {Number} newSize The new size (width for east/west, height for north/south)
35681 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35682 this.panels = new Roo.util.MixedCollection();
35683 this.panels.getKey = this.getPanelId.createDelegate(this);
35685 this.activePanel = null;
35686 // ensure listeners are added...
35688 if (config.listeners || config.events) {
35689 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35690 listeners : config.listeners || {},
35691 events : config.events || {}
35695 if(skipConfig !== true){
35696 this.applyConfig(config);
35700 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35702 getPanelId : function(p){
35706 applyConfig : function(config){
35707 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35708 this.config = config;
35713 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35714 * the width, for horizontal (north, south) the height.
35715 * @param {Number} newSize The new width or height
35717 resizeTo : function(newSize){
35718 var el = this.el ? this.el :
35719 (this.activePanel ? this.activePanel.getEl() : null);
35721 switch(this.position){
35724 el.setWidth(newSize);
35725 this.fireEvent("resized", this, newSize);
35729 el.setHeight(newSize);
35730 this.fireEvent("resized", this, newSize);
35736 getBox : function(){
35737 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35740 getMargins : function(){
35741 return this.margins;
35744 updateBox : function(box){
35746 var el = this.activePanel.getEl();
35747 el.dom.style.left = box.x + "px";
35748 el.dom.style.top = box.y + "px";
35749 this.activePanel.setSize(box.width, box.height);
35753 * Returns the container element for this region.
35754 * @return {Roo.Element}
35756 getEl : function(){
35757 return this.activePanel;
35761 * Returns true if this region is currently visible.
35762 * @return {Boolean}
35764 isVisible : function(){
35765 return this.activePanel ? true : false;
35768 setActivePanel : function(panel){
35769 panel = this.getPanel(panel);
35770 if(this.activePanel && this.activePanel != panel){
35771 this.activePanel.setActiveState(false);
35772 this.activePanel.getEl().setLeftTop(-10000,-10000);
35774 this.activePanel = panel;
35775 panel.setActiveState(true);
35777 panel.setSize(this.box.width, this.box.height);
35779 this.fireEvent("panelactivated", this, panel);
35780 this.fireEvent("invalidated");
35784 * Show the specified panel.
35785 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35786 * @return {Roo.ContentPanel} The shown panel or null
35788 showPanel : function(panel){
35789 panel = this.getPanel(panel);
35791 this.setActivePanel(panel);
35797 * Get the active panel for this region.
35798 * @return {Roo.ContentPanel} The active panel or null
35800 getActivePanel : function(){
35801 return this.activePanel;
35805 * Add the passed ContentPanel(s)
35806 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35807 * @return {Roo.ContentPanel} The panel added (if only one was added)
35809 add : function(panel){
35810 if(arguments.length > 1){
35811 for(var i = 0, len = arguments.length; i < len; i++) {
35812 this.add(arguments[i]);
35816 if(this.hasPanel(panel)){
35817 this.showPanel(panel);
35820 var el = panel.getEl();
35821 if(el.dom.parentNode != this.mgr.el.dom){
35822 this.mgr.el.dom.appendChild(el.dom);
35824 if(panel.setRegion){
35825 panel.setRegion(this);
35827 this.panels.add(panel);
35828 el.setStyle("position", "absolute");
35829 if(!panel.background){
35830 this.setActivePanel(panel);
35831 if(this.config.initialSize && this.panels.getCount()==1){
35832 this.resizeTo(this.config.initialSize);
35835 this.fireEvent("paneladded", this, panel);
35840 * Returns true if the panel is in this region.
35841 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35842 * @return {Boolean}
35844 hasPanel : function(panel){
35845 if(typeof panel == "object"){ // must be panel obj
35846 panel = panel.getId();
35848 return this.getPanel(panel) ? true : false;
35852 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35853 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35854 * @param {Boolean} preservePanel Overrides the config preservePanel option
35855 * @return {Roo.ContentPanel} The panel that was removed
35857 remove : function(panel, preservePanel){
35858 panel = this.getPanel(panel);
35863 this.fireEvent("beforeremove", this, panel, e);
35864 if(e.cancel === true){
35867 var panelId = panel.getId();
35868 this.panels.removeKey(panelId);
35873 * Returns the panel specified or null if it's not in this region.
35874 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35875 * @return {Roo.ContentPanel}
35877 getPanel : function(id){
35878 if(typeof id == "object"){ // must be panel obj
35881 return this.panels.get(id);
35885 * Returns this regions position (north/south/east/west/center).
35888 getPosition: function(){
35889 return this.position;
35893 * Ext JS Library 1.1.1
35894 * Copyright(c) 2006-2007, Ext JS, LLC.
35896 * Originally Released Under LGPL - original licence link has changed is not relivant.
35899 * <script type="text/javascript">
35903 * @class Roo.bootstrap.layout.Region
35904 * @extends Roo.bootstrap.layout.Basic
35905 * This class represents a region in a layout manager.
35907 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35908 * @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})
35909 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35910 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35911 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35912 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35913 * @cfg {String} title The title for the region (overrides panel titles)
35914 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35915 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35916 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35917 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35918 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35919 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35920 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35921 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35922 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35923 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35925 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35926 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35927 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35928 * @cfg {Number} width For East/West panels
35929 * @cfg {Number} height For North/South panels
35930 * @cfg {Boolean} split To show the splitter
35931 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35933 * @cfg {string} cls Extra CSS classes to add to region
35935 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35936 * @cfg {string} region the region that it inhabits..
35939 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35940 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35942 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35943 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35944 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35946 Roo.bootstrap.layout.Region = function(config)
35948 this.applyConfig(config);
35950 var mgr = config.mgr;
35951 var pos = config.region;
35952 config.skipConfig = true;
35953 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35956 this.onRender(mgr.el);
35959 this.visible = true;
35960 this.collapsed = false;
35961 this.unrendered_panels = [];
35964 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35966 position: '', // set by wrapper (eg. north/south etc..)
35967 unrendered_panels : null, // unrendered panels.
35969 tabPosition : false,
35971 mgr: false, // points to 'Border'
35974 createBody : function(){
35975 /** This region's body element
35976 * @type Roo.Element */
35977 this.bodyEl = this.el.createChild({
35979 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35983 onRender: function(ctr, pos)
35985 var dh = Roo.DomHelper;
35986 /** This region's container element
35987 * @type Roo.Element */
35988 this.el = dh.append(ctr.dom, {
35990 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35992 /** This region's title element
35993 * @type Roo.Element */
35995 this.titleEl = dh.append(this.el.dom, {
35997 unselectable: "on",
35998 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36000 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36001 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36005 this.titleEl.enableDisplayMode();
36006 /** This region's title text element
36007 * @type HTMLElement */
36008 this.titleTextEl = this.titleEl.dom.firstChild;
36009 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36011 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36012 this.closeBtn.enableDisplayMode();
36013 this.closeBtn.on("click", this.closeClicked, this);
36014 this.closeBtn.hide();
36016 this.createBody(this.config);
36017 if(this.config.hideWhenEmpty){
36019 this.on("paneladded", this.validateVisibility, this);
36020 this.on("panelremoved", this.validateVisibility, this);
36022 if(this.autoScroll){
36023 this.bodyEl.setStyle("overflow", "auto");
36025 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36027 //if(c.titlebar !== false){
36028 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36029 this.titleEl.hide();
36031 this.titleEl.show();
36032 if(this.config.title){
36033 this.titleTextEl.innerHTML = this.config.title;
36037 if(this.config.collapsed){
36038 this.collapse(true);
36040 if(this.config.hidden){
36044 if (this.unrendered_panels && this.unrendered_panels.length) {
36045 for (var i =0;i< this.unrendered_panels.length; i++) {
36046 this.add(this.unrendered_panels[i]);
36048 this.unrendered_panels = null;
36054 applyConfig : function(c)
36057 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36058 var dh = Roo.DomHelper;
36059 if(c.titlebar !== false){
36060 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36061 this.collapseBtn.on("click", this.collapse, this);
36062 this.collapseBtn.enableDisplayMode();
36064 if(c.showPin === true || this.showPin){
36065 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36066 this.stickBtn.enableDisplayMode();
36067 this.stickBtn.on("click", this.expand, this);
36068 this.stickBtn.hide();
36073 /** This region's collapsed element
36074 * @type Roo.Element */
36077 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36078 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36081 if(c.floatable !== false){
36082 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36083 this.collapsedEl.on("click", this.collapseClick, this);
36086 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36087 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36088 id: "message", unselectable: "on", style:{"float":"left"}});
36089 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36091 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36092 this.expandBtn.on("click", this.expand, this);
36096 if(this.collapseBtn){
36097 this.collapseBtn.setVisible(c.collapsible == true);
36100 this.cmargins = c.cmargins || this.cmargins ||
36101 (this.position == "west" || this.position == "east" ?
36102 {top: 0, left: 2, right:2, bottom: 0} :
36103 {top: 2, left: 0, right:0, bottom: 2});
36105 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36108 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36110 this.autoScroll = c.autoScroll || false;
36115 this.duration = c.duration || .30;
36116 this.slideDuration = c.slideDuration || .45;
36121 * Returns true if this region is currently visible.
36122 * @return {Boolean}
36124 isVisible : function(){
36125 return this.visible;
36129 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36130 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36132 //setCollapsedTitle : function(title){
36133 // title = title || " ";
36134 // if(this.collapsedTitleTextEl){
36135 // this.collapsedTitleTextEl.innerHTML = title;
36139 getBox : function(){
36141 // if(!this.collapsed){
36142 b = this.el.getBox(false, true);
36144 // b = this.collapsedEl.getBox(false, true);
36149 getMargins : function(){
36150 return this.margins;
36151 //return this.collapsed ? this.cmargins : this.margins;
36154 highlight : function(){
36155 this.el.addClass("x-layout-panel-dragover");
36158 unhighlight : function(){
36159 this.el.removeClass("x-layout-panel-dragover");
36162 updateBox : function(box)
36164 if (!this.bodyEl) {
36165 return; // not rendered yet..
36169 if(!this.collapsed){
36170 this.el.dom.style.left = box.x + "px";
36171 this.el.dom.style.top = box.y + "px";
36172 this.updateBody(box.width, box.height);
36174 this.collapsedEl.dom.style.left = box.x + "px";
36175 this.collapsedEl.dom.style.top = box.y + "px";
36176 this.collapsedEl.setSize(box.width, box.height);
36179 this.tabs.autoSizeTabs();
36183 updateBody : function(w, h)
36186 this.el.setWidth(w);
36187 w -= this.el.getBorderWidth("rl");
36188 if(this.config.adjustments){
36189 w += this.config.adjustments[0];
36192 if(h !== null && h > 0){
36193 this.el.setHeight(h);
36194 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36195 h -= this.el.getBorderWidth("tb");
36196 if(this.config.adjustments){
36197 h += this.config.adjustments[1];
36199 this.bodyEl.setHeight(h);
36201 h = this.tabs.syncHeight(h);
36204 if(this.panelSize){
36205 w = w !== null ? w : this.panelSize.width;
36206 h = h !== null ? h : this.panelSize.height;
36208 if(this.activePanel){
36209 var el = this.activePanel.getEl();
36210 w = w !== null ? w : el.getWidth();
36211 h = h !== null ? h : el.getHeight();
36212 this.panelSize = {width: w, height: h};
36213 this.activePanel.setSize(w, h);
36215 if(Roo.isIE && this.tabs){
36216 this.tabs.el.repaint();
36221 * Returns the container element for this region.
36222 * @return {Roo.Element}
36224 getEl : function(){
36229 * Hides this region.
36232 //if(!this.collapsed){
36233 this.el.dom.style.left = "-2000px";
36236 // this.collapsedEl.dom.style.left = "-2000px";
36237 // this.collapsedEl.hide();
36239 this.visible = false;
36240 this.fireEvent("visibilitychange", this, false);
36244 * Shows this region if it was previously hidden.
36247 //if(!this.collapsed){
36250 // this.collapsedEl.show();
36252 this.visible = true;
36253 this.fireEvent("visibilitychange", this, true);
36256 closeClicked : function(){
36257 if(this.activePanel){
36258 this.remove(this.activePanel);
36262 collapseClick : function(e){
36264 e.stopPropagation();
36267 e.stopPropagation();
36273 * Collapses this region.
36274 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36277 collapse : function(skipAnim, skipCheck = false){
36278 if(this.collapsed) {
36282 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36284 this.collapsed = true;
36286 this.split.el.hide();
36288 if(this.config.animate && skipAnim !== true){
36289 this.fireEvent("invalidated", this);
36290 this.animateCollapse();
36292 this.el.setLocation(-20000,-20000);
36294 this.collapsedEl.show();
36295 this.fireEvent("collapsed", this);
36296 this.fireEvent("invalidated", this);
36302 animateCollapse : function(){
36307 * Expands this region if it was previously collapsed.
36308 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36309 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36312 expand : function(e, skipAnim){
36314 e.stopPropagation();
36316 if(!this.collapsed || this.el.hasActiveFx()) {
36320 this.afterSlideIn();
36323 this.collapsed = false;
36324 if(this.config.animate && skipAnim !== true){
36325 this.animateExpand();
36329 this.split.el.show();
36331 this.collapsedEl.setLocation(-2000,-2000);
36332 this.collapsedEl.hide();
36333 this.fireEvent("invalidated", this);
36334 this.fireEvent("expanded", this);
36338 animateExpand : function(){
36342 initTabs : function()
36344 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36346 var ts = new Roo.bootstrap.panel.Tabs({
36347 el: this.bodyEl.dom,
36349 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36350 disableTooltips: this.config.disableTabTips,
36351 toolbar : this.config.toolbar
36354 if(this.config.hideTabs){
36355 ts.stripWrap.setDisplayed(false);
36358 ts.resizeTabs = this.config.resizeTabs === true;
36359 ts.minTabWidth = this.config.minTabWidth || 40;
36360 ts.maxTabWidth = this.config.maxTabWidth || 250;
36361 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36362 ts.monitorResize = false;
36363 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36364 ts.bodyEl.addClass('roo-layout-tabs-body');
36365 this.panels.each(this.initPanelAsTab, this);
36368 initPanelAsTab : function(panel){
36369 var ti = this.tabs.addTab(
36373 this.config.closeOnTab && panel.isClosable(),
36376 if(panel.tabTip !== undefined){
36377 ti.setTooltip(panel.tabTip);
36379 ti.on("activate", function(){
36380 this.setActivePanel(panel);
36383 if(this.config.closeOnTab){
36384 ti.on("beforeclose", function(t, e){
36386 this.remove(panel);
36390 panel.tabItem = ti;
36395 updatePanelTitle : function(panel, title)
36397 if(this.activePanel == panel){
36398 this.updateTitle(title);
36401 var ti = this.tabs.getTab(panel.getEl().id);
36403 if(panel.tabTip !== undefined){
36404 ti.setTooltip(panel.tabTip);
36409 updateTitle : function(title){
36410 if(this.titleTextEl && !this.config.title){
36411 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36415 setActivePanel : function(panel)
36417 panel = this.getPanel(panel);
36418 if(this.activePanel && this.activePanel != panel){
36419 if(this.activePanel.setActiveState(false) === false){
36423 this.activePanel = panel;
36424 panel.setActiveState(true);
36425 if(this.panelSize){
36426 panel.setSize(this.panelSize.width, this.panelSize.height);
36429 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36431 this.updateTitle(panel.getTitle());
36433 this.fireEvent("invalidated", this);
36435 this.fireEvent("panelactivated", this, panel);
36439 * Shows the specified panel.
36440 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36441 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36443 showPanel : function(panel)
36445 panel = this.getPanel(panel);
36448 var tab = this.tabs.getTab(panel.getEl().id);
36449 if(tab.isHidden()){
36450 this.tabs.unhideTab(tab.id);
36454 this.setActivePanel(panel);
36461 * Get the active panel for this region.
36462 * @return {Roo.ContentPanel} The active panel or null
36464 getActivePanel : function(){
36465 return this.activePanel;
36468 validateVisibility : function(){
36469 if(this.panels.getCount() < 1){
36470 this.updateTitle(" ");
36471 this.closeBtn.hide();
36474 if(!this.isVisible()){
36481 * Adds the passed ContentPanel(s) to this region.
36482 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36483 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36485 add : function(panel)
36487 if(arguments.length > 1){
36488 for(var i = 0, len = arguments.length; i < len; i++) {
36489 this.add(arguments[i]);
36494 // if we have not been rendered yet, then we can not really do much of this..
36495 if (!this.bodyEl) {
36496 this.unrendered_panels.push(panel);
36503 if(this.hasPanel(panel)){
36504 this.showPanel(panel);
36507 panel.setRegion(this);
36508 this.panels.add(panel);
36509 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36510 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36511 // and hide them... ???
36512 this.bodyEl.dom.appendChild(panel.getEl().dom);
36513 if(panel.background !== true){
36514 this.setActivePanel(panel);
36516 this.fireEvent("paneladded", this, panel);
36523 this.initPanelAsTab(panel);
36527 if(panel.background !== true){
36528 this.tabs.activate(panel.getEl().id);
36530 this.fireEvent("paneladded", this, panel);
36535 * Hides the tab for the specified panel.
36536 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36538 hidePanel : function(panel){
36539 if(this.tabs && (panel = this.getPanel(panel))){
36540 this.tabs.hideTab(panel.getEl().id);
36545 * Unhides the tab for a previously hidden panel.
36546 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36548 unhidePanel : function(panel){
36549 if(this.tabs && (panel = this.getPanel(panel))){
36550 this.tabs.unhideTab(panel.getEl().id);
36554 clearPanels : function(){
36555 while(this.panels.getCount() > 0){
36556 this.remove(this.panels.first());
36561 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36562 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36563 * @param {Boolean} preservePanel Overrides the config preservePanel option
36564 * @return {Roo.ContentPanel} The panel that was removed
36566 remove : function(panel, preservePanel)
36568 panel = this.getPanel(panel);
36573 this.fireEvent("beforeremove", this, panel, e);
36574 if(e.cancel === true){
36577 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36578 var panelId = panel.getId();
36579 this.panels.removeKey(panelId);
36581 document.body.appendChild(panel.getEl().dom);
36584 this.tabs.removeTab(panel.getEl().id);
36585 }else if (!preservePanel){
36586 this.bodyEl.dom.removeChild(panel.getEl().dom);
36588 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36589 var p = this.panels.first();
36590 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36591 tempEl.appendChild(p.getEl().dom);
36592 this.bodyEl.update("");
36593 this.bodyEl.dom.appendChild(p.getEl().dom);
36595 this.updateTitle(p.getTitle());
36597 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36598 this.setActivePanel(p);
36600 panel.setRegion(null);
36601 if(this.activePanel == panel){
36602 this.activePanel = null;
36604 if(this.config.autoDestroy !== false && preservePanel !== true){
36605 try{panel.destroy();}catch(e){}
36607 this.fireEvent("panelremoved", this, panel);
36612 * Returns the TabPanel component used by this region
36613 * @return {Roo.TabPanel}
36615 getTabs : function(){
36619 createTool : function(parentEl, className){
36620 var btn = Roo.DomHelper.append(parentEl, {
36622 cls: "x-layout-tools-button",
36625 cls: "roo-layout-tools-button-inner " + className,
36629 btn.addClassOnOver("roo-layout-tools-button-over");
36634 * Ext JS Library 1.1.1
36635 * Copyright(c) 2006-2007, Ext JS, LLC.
36637 * Originally Released Under LGPL - original licence link has changed is not relivant.
36640 * <script type="text/javascript">
36646 * @class Roo.SplitLayoutRegion
36647 * @extends Roo.LayoutRegion
36648 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36650 Roo.bootstrap.layout.Split = function(config){
36651 this.cursor = config.cursor;
36652 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36655 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36657 splitTip : "Drag to resize.",
36658 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36659 useSplitTips : false,
36661 applyConfig : function(config){
36662 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36665 onRender : function(ctr,pos) {
36667 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36668 if(!this.config.split){
36673 var splitEl = Roo.DomHelper.append(ctr.dom, {
36675 id: this.el.id + "-split",
36676 cls: "roo-layout-split roo-layout-split-"+this.position,
36679 /** The SplitBar for this region
36680 * @type Roo.SplitBar */
36681 // does not exist yet...
36682 Roo.log([this.position, this.orientation]);
36684 this.split = new Roo.bootstrap.SplitBar({
36685 dragElement : splitEl,
36686 resizingElement: this.el,
36687 orientation : this.orientation
36690 this.split.on("moved", this.onSplitMove, this);
36691 this.split.useShim = this.config.useShim === true;
36692 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36693 if(this.useSplitTips){
36694 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36696 //if(config.collapsible){
36697 // this.split.el.on("dblclick", this.collapse, this);
36700 if(typeof this.config.minSize != "undefined"){
36701 this.split.minSize = this.config.minSize;
36703 if(typeof this.config.maxSize != "undefined"){
36704 this.split.maxSize = this.config.maxSize;
36706 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36707 this.hideSplitter();
36712 getHMaxSize : function(){
36713 var cmax = this.config.maxSize || 10000;
36714 var center = this.mgr.getRegion("center");
36715 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36718 getVMaxSize : function(){
36719 var cmax = this.config.maxSize || 10000;
36720 var center = this.mgr.getRegion("center");
36721 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36724 onSplitMove : function(split, newSize){
36725 this.fireEvent("resized", this, newSize);
36729 * Returns the {@link Roo.SplitBar} for this region.
36730 * @return {Roo.SplitBar}
36732 getSplitBar : function(){
36737 this.hideSplitter();
36738 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36741 hideSplitter : function(){
36743 this.split.el.setLocation(-2000,-2000);
36744 this.split.el.hide();
36750 this.split.el.show();
36752 Roo.bootstrap.layout.Split.superclass.show.call(this);
36755 beforeSlide: function(){
36756 if(Roo.isGecko){// firefox overflow auto bug workaround
36757 this.bodyEl.clip();
36759 this.tabs.bodyEl.clip();
36761 if(this.activePanel){
36762 this.activePanel.getEl().clip();
36764 if(this.activePanel.beforeSlide){
36765 this.activePanel.beforeSlide();
36771 afterSlide : function(){
36772 if(Roo.isGecko){// firefox overflow auto bug workaround
36773 this.bodyEl.unclip();
36775 this.tabs.bodyEl.unclip();
36777 if(this.activePanel){
36778 this.activePanel.getEl().unclip();
36779 if(this.activePanel.afterSlide){
36780 this.activePanel.afterSlide();
36786 initAutoHide : function(){
36787 if(this.autoHide !== false){
36788 if(!this.autoHideHd){
36789 var st = new Roo.util.DelayedTask(this.slideIn, this);
36790 this.autoHideHd = {
36791 "mouseout": function(e){
36792 if(!e.within(this.el, true)){
36796 "mouseover" : function(e){
36802 this.el.on(this.autoHideHd);
36806 clearAutoHide : function(){
36807 if(this.autoHide !== false){
36808 this.el.un("mouseout", this.autoHideHd.mouseout);
36809 this.el.un("mouseover", this.autoHideHd.mouseover);
36813 clearMonitor : function(){
36814 Roo.get(document).un("click", this.slideInIf, this);
36817 // these names are backwards but not changed for compat
36818 slideOut : function(){
36819 if(this.isSlid || this.el.hasActiveFx()){
36822 this.isSlid = true;
36823 if(this.collapseBtn){
36824 this.collapseBtn.hide();
36826 this.closeBtnState = this.closeBtn.getStyle('display');
36827 this.closeBtn.hide();
36829 this.stickBtn.show();
36832 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36833 this.beforeSlide();
36834 this.el.setStyle("z-index", 10001);
36835 this.el.slideIn(this.getSlideAnchor(), {
36836 callback: function(){
36838 this.initAutoHide();
36839 Roo.get(document).on("click", this.slideInIf, this);
36840 this.fireEvent("slideshow", this);
36847 afterSlideIn : function(){
36848 this.clearAutoHide();
36849 this.isSlid = false;
36850 this.clearMonitor();
36851 this.el.setStyle("z-index", "");
36852 if(this.collapseBtn){
36853 this.collapseBtn.show();
36855 this.closeBtn.setStyle('display', this.closeBtnState);
36857 this.stickBtn.hide();
36859 this.fireEvent("slidehide", this);
36862 slideIn : function(cb){
36863 if(!this.isSlid || this.el.hasActiveFx()){
36867 this.isSlid = false;
36868 this.beforeSlide();
36869 this.el.slideOut(this.getSlideAnchor(), {
36870 callback: function(){
36871 this.el.setLeftTop(-10000, -10000);
36873 this.afterSlideIn();
36881 slideInIf : function(e){
36882 if(!e.within(this.el)){
36887 animateCollapse : function(){
36888 this.beforeSlide();
36889 this.el.setStyle("z-index", 20000);
36890 var anchor = this.getSlideAnchor();
36891 this.el.slideOut(anchor, {
36892 callback : function(){
36893 this.el.setStyle("z-index", "");
36894 this.collapsedEl.slideIn(anchor, {duration:.3});
36896 this.el.setLocation(-10000,-10000);
36898 this.fireEvent("collapsed", this);
36905 animateExpand : function(){
36906 this.beforeSlide();
36907 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36908 this.el.setStyle("z-index", 20000);
36909 this.collapsedEl.hide({
36912 this.el.slideIn(this.getSlideAnchor(), {
36913 callback : function(){
36914 this.el.setStyle("z-index", "");
36917 this.split.el.show();
36919 this.fireEvent("invalidated", this);
36920 this.fireEvent("expanded", this);
36948 getAnchor : function(){
36949 return this.anchors[this.position];
36952 getCollapseAnchor : function(){
36953 return this.canchors[this.position];
36956 getSlideAnchor : function(){
36957 return this.sanchors[this.position];
36960 getAlignAdj : function(){
36961 var cm = this.cmargins;
36962 switch(this.position){
36978 getExpandAdj : function(){
36979 var c = this.collapsedEl, cm = this.cmargins;
36980 switch(this.position){
36982 return [-(cm.right+c.getWidth()+cm.left), 0];
36985 return [cm.right+c.getWidth()+cm.left, 0];
36988 return [0, -(cm.top+cm.bottom+c.getHeight())];
36991 return [0, cm.top+cm.bottom+c.getHeight()];
36997 * Ext JS Library 1.1.1
36998 * Copyright(c) 2006-2007, Ext JS, LLC.
37000 * Originally Released Under LGPL - original licence link has changed is not relivant.
37003 * <script type="text/javascript">
37006 * These classes are private internal classes
37008 Roo.bootstrap.layout.Center = function(config){
37009 config.region = "center";
37010 Roo.bootstrap.layout.Region.call(this, config);
37011 this.visible = true;
37012 this.minWidth = config.minWidth || 20;
37013 this.minHeight = config.minHeight || 20;
37016 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37018 // center panel can't be hidden
37022 // center panel can't be hidden
37025 getMinWidth: function(){
37026 return this.minWidth;
37029 getMinHeight: function(){
37030 return this.minHeight;
37044 Roo.bootstrap.layout.North = function(config)
37046 config.region = 'north';
37047 config.cursor = 'n-resize';
37049 Roo.bootstrap.layout.Split.call(this, config);
37053 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37054 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37055 this.split.el.addClass("roo-layout-split-v");
37057 var size = config.initialSize || config.height;
37058 if(typeof size != "undefined"){
37059 this.el.setHeight(size);
37062 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37064 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37068 getBox : function(){
37069 if(this.collapsed){
37070 return this.collapsedEl.getBox();
37072 var box = this.el.getBox();
37074 box.height += this.split.el.getHeight();
37079 updateBox : function(box){
37080 if(this.split && !this.collapsed){
37081 box.height -= this.split.el.getHeight();
37082 this.split.el.setLeft(box.x);
37083 this.split.el.setTop(box.y+box.height);
37084 this.split.el.setWidth(box.width);
37086 if(this.collapsed){
37087 this.updateBody(box.width, null);
37089 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37097 Roo.bootstrap.layout.South = function(config){
37098 config.region = 'south';
37099 config.cursor = 's-resize';
37100 Roo.bootstrap.layout.Split.call(this, config);
37102 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37103 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37104 this.split.el.addClass("roo-layout-split-v");
37106 var size = config.initialSize || config.height;
37107 if(typeof size != "undefined"){
37108 this.el.setHeight(size);
37112 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37113 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37114 getBox : function(){
37115 if(this.collapsed){
37116 return this.collapsedEl.getBox();
37118 var box = this.el.getBox();
37120 var sh = this.split.el.getHeight();
37127 updateBox : function(box){
37128 if(this.split && !this.collapsed){
37129 var sh = this.split.el.getHeight();
37132 this.split.el.setLeft(box.x);
37133 this.split.el.setTop(box.y-sh);
37134 this.split.el.setWidth(box.width);
37136 if(this.collapsed){
37137 this.updateBody(box.width, null);
37139 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37143 Roo.bootstrap.layout.East = function(config){
37144 config.region = "east";
37145 config.cursor = "e-resize";
37146 Roo.bootstrap.layout.Split.call(this, config);
37148 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37149 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37150 this.split.el.addClass("roo-layout-split-h");
37152 var size = config.initialSize || config.width;
37153 if(typeof size != "undefined"){
37154 this.el.setWidth(size);
37157 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37158 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37159 getBox : function(){
37160 if(this.collapsed){
37161 return this.collapsedEl.getBox();
37163 var box = this.el.getBox();
37165 var sw = this.split.el.getWidth();
37172 updateBox : function(box){
37173 if(this.split && !this.collapsed){
37174 var sw = this.split.el.getWidth();
37176 this.split.el.setLeft(box.x);
37177 this.split.el.setTop(box.y);
37178 this.split.el.setHeight(box.height);
37181 if(this.collapsed){
37182 this.updateBody(null, box.height);
37184 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37188 Roo.bootstrap.layout.West = function(config){
37189 config.region = "west";
37190 config.cursor = "w-resize";
37192 Roo.bootstrap.layout.Split.call(this, config);
37194 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37195 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37196 this.split.el.addClass("roo-layout-split-h");
37200 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37201 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37203 onRender: function(ctr, pos)
37205 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37206 var size = this.config.initialSize || this.config.width;
37207 if(typeof size != "undefined"){
37208 this.el.setWidth(size);
37212 getBox : function(){
37213 if(this.collapsed){
37214 return this.collapsedEl.getBox();
37216 var box = this.el.getBox();
37218 box.width += this.split.el.getWidth();
37223 updateBox : function(box){
37224 if(this.split && !this.collapsed){
37225 var sw = this.split.el.getWidth();
37227 this.split.el.setLeft(box.x+box.width);
37228 this.split.el.setTop(box.y);
37229 this.split.el.setHeight(box.height);
37231 if(this.collapsed){
37232 this.updateBody(null, box.height);
37234 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37236 });Roo.namespace("Roo.bootstrap.panel");/*
37238 * Ext JS Library 1.1.1
37239 * Copyright(c) 2006-2007, Ext JS, LLC.
37241 * Originally Released Under LGPL - original licence link has changed is not relivant.
37244 * <script type="text/javascript">
37247 * @class Roo.ContentPanel
37248 * @extends Roo.util.Observable
37249 * A basic ContentPanel element.
37250 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37251 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37252 * @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
37253 * @cfg {Boolean} closable True if the panel can be closed/removed
37254 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37255 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37256 * @cfg {Toolbar} toolbar A toolbar for this panel
37257 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37258 * @cfg {String} title The title for this panel
37259 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37260 * @cfg {String} url Calls {@link #setUrl} with this value
37261 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37262 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37263 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37264 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37265 * @cfg {Boolean} badges render the badges
37268 * Create a new ContentPanel.
37269 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37270 * @param {String/Object} config A string to set only the title or a config object
37271 * @param {String} content (optional) Set the HTML content for this panel
37272 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37274 Roo.bootstrap.panel.Content = function( config){
37276 this.tpl = config.tpl || false;
37278 var el = config.el;
37279 var content = config.content;
37281 if(config.autoCreate){ // xtype is available if this is called from factory
37284 this.el = Roo.get(el);
37285 if(!this.el && config && config.autoCreate){
37286 if(typeof config.autoCreate == "object"){
37287 if(!config.autoCreate.id){
37288 config.autoCreate.id = config.id||el;
37290 this.el = Roo.DomHelper.append(document.body,
37291 config.autoCreate, true);
37293 var elcfg = { tag: "div",
37294 cls: "roo-layout-inactive-content",
37298 elcfg.html = config.html;
37302 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37305 this.closable = false;
37306 this.loaded = false;
37307 this.active = false;
37310 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37312 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37314 this.wrapEl = this.el; //this.el.wrap();
37316 if (config.toolbar.items) {
37317 ti = config.toolbar.items ;
37318 delete config.toolbar.items ;
37322 this.toolbar.render(this.wrapEl, 'before');
37323 for(var i =0;i < ti.length;i++) {
37324 // Roo.log(['add child', items[i]]);
37325 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37327 this.toolbar.items = nitems;
37328 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37329 delete config.toolbar;
37333 // xtype created footer. - not sure if will work as we normally have to render first..
37334 if (this.footer && !this.footer.el && this.footer.xtype) {
37335 if (!this.wrapEl) {
37336 this.wrapEl = this.el.wrap();
37339 this.footer.container = this.wrapEl.createChild();
37341 this.footer = Roo.factory(this.footer, Roo);
37346 if(typeof config == "string"){
37347 this.title = config;
37349 Roo.apply(this, config);
37353 this.resizeEl = Roo.get(this.resizeEl, true);
37355 this.resizeEl = this.el;
37357 // handle view.xtype
37365 * Fires when this panel is activated.
37366 * @param {Roo.ContentPanel} this
37370 * @event deactivate
37371 * Fires when this panel is activated.
37372 * @param {Roo.ContentPanel} this
37374 "deactivate" : true,
37378 * Fires when this panel is resized if fitToFrame is true.
37379 * @param {Roo.ContentPanel} this
37380 * @param {Number} width The width after any component adjustments
37381 * @param {Number} height The height after any component adjustments
37387 * Fires when this tab is created
37388 * @param {Roo.ContentPanel} this
37399 if(this.autoScroll){
37400 this.resizeEl.setStyle("overflow", "auto");
37402 // fix randome scrolling
37403 //this.el.on('scroll', function() {
37404 // Roo.log('fix random scolling');
37405 // this.scrollTo('top',0);
37408 content = content || this.content;
37410 this.setContent(content);
37412 if(config && config.url){
37413 this.setUrl(this.url, this.params, this.loadOnce);
37418 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37420 if (this.view && typeof(this.view.xtype) != 'undefined') {
37421 this.view.el = this.el.appendChild(document.createElement("div"));
37422 this.view = Roo.factory(this.view);
37423 this.view.render && this.view.render(false, '');
37427 this.fireEvent('render', this);
37430 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37434 setRegion : function(region){
37435 this.region = region;
37436 this.setActiveClass(region && !this.background);
37440 setActiveClass: function(state)
37443 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37444 this.el.setStyle('position','relative');
37446 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37447 this.el.setStyle('position', 'absolute');
37452 * Returns the toolbar for this Panel if one was configured.
37453 * @return {Roo.Toolbar}
37455 getToolbar : function(){
37456 return this.toolbar;
37459 setActiveState : function(active)
37461 this.active = active;
37462 this.setActiveClass(active);
37464 if(this.fireEvent("deactivate", this) === false){
37469 this.fireEvent("activate", this);
37473 * Updates this panel's element
37474 * @param {String} content The new content
37475 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37477 setContent : function(content, loadScripts){
37478 this.el.update(content, loadScripts);
37481 ignoreResize : function(w, h){
37482 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37485 this.lastSize = {width: w, height: h};
37490 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37491 * @return {Roo.UpdateManager} The UpdateManager
37493 getUpdateManager : function(){
37494 return this.el.getUpdateManager();
37497 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37498 * @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:
37501 url: "your-url.php",
37502 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37503 callback: yourFunction,
37504 scope: yourObject, //(optional scope)
37507 text: "Loading...",
37512 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37513 * 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.
37514 * @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}
37515 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37516 * @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.
37517 * @return {Roo.ContentPanel} this
37520 var um = this.el.getUpdateManager();
37521 um.update.apply(um, arguments);
37527 * 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.
37528 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37529 * @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)
37530 * @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)
37531 * @return {Roo.UpdateManager} The UpdateManager
37533 setUrl : function(url, params, loadOnce){
37534 if(this.refreshDelegate){
37535 this.removeListener("activate", this.refreshDelegate);
37537 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37538 this.on("activate", this.refreshDelegate);
37539 return this.el.getUpdateManager();
37542 _handleRefresh : function(url, params, loadOnce){
37543 if(!loadOnce || !this.loaded){
37544 var updater = this.el.getUpdateManager();
37545 updater.update(url, params, this._setLoaded.createDelegate(this));
37549 _setLoaded : function(){
37550 this.loaded = true;
37554 * Returns this panel's id
37557 getId : function(){
37562 * Returns this panel's element - used by regiosn to add.
37563 * @return {Roo.Element}
37565 getEl : function(){
37566 return this.wrapEl || this.el;
37571 adjustForComponents : function(width, height)
37573 //Roo.log('adjustForComponents ');
37574 if(this.resizeEl != this.el){
37575 width -= this.el.getFrameWidth('lr');
37576 height -= this.el.getFrameWidth('tb');
37579 var te = this.toolbar.getEl();
37580 te.setWidth(width);
37581 height -= te.getHeight();
37584 var te = this.footer.getEl();
37585 te.setWidth(width);
37586 height -= te.getHeight();
37590 if(this.adjustments){
37591 width += this.adjustments[0];
37592 height += this.adjustments[1];
37594 return {"width": width, "height": height};
37597 setSize : function(width, height){
37598 if(this.fitToFrame && !this.ignoreResize(width, height)){
37599 if(this.fitContainer && this.resizeEl != this.el){
37600 this.el.setSize(width, height);
37602 var size = this.adjustForComponents(width, height);
37603 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37604 this.fireEvent('resize', this, size.width, size.height);
37609 * Returns this panel's title
37612 getTitle : function(){
37614 if (typeof(this.title) != 'object') {
37619 for (var k in this.title) {
37620 if (!this.title.hasOwnProperty(k)) {
37624 if (k.indexOf('-') >= 0) {
37625 var s = k.split('-');
37626 for (var i = 0; i<s.length; i++) {
37627 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37630 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37637 * Set this panel's title
37638 * @param {String} title
37640 setTitle : function(title){
37641 this.title = title;
37643 this.region.updatePanelTitle(this, title);
37648 * Returns true is this panel was configured to be closable
37649 * @return {Boolean}
37651 isClosable : function(){
37652 return this.closable;
37655 beforeSlide : function(){
37657 this.resizeEl.clip();
37660 afterSlide : function(){
37662 this.resizeEl.unclip();
37666 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37667 * Will fail silently if the {@link #setUrl} method has not been called.
37668 * This does not activate the panel, just updates its content.
37670 refresh : function(){
37671 if(this.refreshDelegate){
37672 this.loaded = false;
37673 this.refreshDelegate();
37678 * Destroys this panel
37680 destroy : function(){
37681 this.el.removeAllListeners();
37682 var tempEl = document.createElement("span");
37683 tempEl.appendChild(this.el.dom);
37684 tempEl.innerHTML = "";
37690 * form - if the content panel contains a form - this is a reference to it.
37691 * @type {Roo.form.Form}
37695 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37696 * This contains a reference to it.
37702 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37712 * @param {Object} cfg Xtype definition of item to add.
37716 getChildContainer: function () {
37717 return this.getEl();
37722 var ret = new Roo.factory(cfg);
37727 if (cfg.xtype.match(/^Form$/)) {
37730 //if (this.footer) {
37731 // el = this.footer.container.insertSibling(false, 'before');
37733 el = this.el.createChild();
37736 this.form = new Roo.form.Form(cfg);
37739 if ( this.form.allItems.length) {
37740 this.form.render(el.dom);
37744 // should only have one of theses..
37745 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37746 // views.. should not be just added - used named prop 'view''
37748 cfg.el = this.el.appendChild(document.createElement("div"));
37751 var ret = new Roo.factory(cfg);
37753 ret.render && ret.render(false, ''); // render blank..
37763 * @class Roo.bootstrap.panel.Grid
37764 * @extends Roo.bootstrap.panel.Content
37766 * Create a new GridPanel.
37767 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37768 * @param {Object} config A the config object
37774 Roo.bootstrap.panel.Grid = function(config)
37778 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37779 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37781 config.el = this.wrapper;
37782 //this.el = this.wrapper;
37784 if (config.container) {
37785 // ctor'ed from a Border/panel.grid
37788 this.wrapper.setStyle("overflow", "hidden");
37789 this.wrapper.addClass('roo-grid-container');
37794 if(config.toolbar){
37795 var tool_el = this.wrapper.createChild();
37796 this.toolbar = Roo.factory(config.toolbar);
37798 if (config.toolbar.items) {
37799 ti = config.toolbar.items ;
37800 delete config.toolbar.items ;
37804 this.toolbar.render(tool_el);
37805 for(var i =0;i < ti.length;i++) {
37806 // Roo.log(['add child', items[i]]);
37807 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37809 this.toolbar.items = nitems;
37811 delete config.toolbar;
37814 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37815 config.grid.scrollBody = true;;
37816 config.grid.monitorWindowResize = false; // turn off autosizing
37817 config.grid.autoHeight = false;
37818 config.grid.autoWidth = false;
37820 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37822 if (config.background) {
37823 // render grid on panel activation (if panel background)
37824 this.on('activate', function(gp) {
37825 if (!gp.grid.rendered) {
37826 gp.grid.render(this.wrapper);
37827 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37832 this.grid.render(this.wrapper);
37833 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37836 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37837 // ??? needed ??? config.el = this.wrapper;
37842 // xtype created footer. - not sure if will work as we normally have to render first..
37843 if (this.footer && !this.footer.el && this.footer.xtype) {
37845 var ctr = this.grid.getView().getFooterPanel(true);
37846 this.footer.dataSource = this.grid.dataSource;
37847 this.footer = Roo.factory(this.footer, Roo);
37848 this.footer.render(ctr);
37858 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37859 getId : function(){
37860 return this.grid.id;
37864 * Returns the grid for this panel
37865 * @return {Roo.bootstrap.Table}
37867 getGrid : function(){
37871 setSize : function(width, height){
37872 if(!this.ignoreResize(width, height)){
37873 var grid = this.grid;
37874 var size = this.adjustForComponents(width, height);
37875 var gridel = grid.getGridEl();
37876 gridel.setSize(size.width, size.height);
37878 var thd = grid.getGridEl().select('thead',true).first();
37879 var tbd = grid.getGridEl().select('tbody', true).first();
37881 tbd.setSize(width, height - thd.getHeight());
37890 beforeSlide : function(){
37891 this.grid.getView().scroller.clip();
37894 afterSlide : function(){
37895 this.grid.getView().scroller.unclip();
37898 destroy : function(){
37899 this.grid.destroy();
37901 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37906 * @class Roo.bootstrap.panel.Nest
37907 * @extends Roo.bootstrap.panel.Content
37909 * Create a new Panel, that can contain a layout.Border.
37912 * @param {Roo.BorderLayout} layout The layout for this panel
37913 * @param {String/Object} config A string to set only the title or a config object
37915 Roo.bootstrap.panel.Nest = function(config)
37917 // construct with only one argument..
37918 /* FIXME - implement nicer consturctors
37919 if (layout.layout) {
37921 layout = config.layout;
37922 delete config.layout;
37924 if (layout.xtype && !layout.getEl) {
37925 // then layout needs constructing..
37926 layout = Roo.factory(layout, Roo);
37930 config.el = config.layout.getEl();
37932 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37934 config.layout.monitorWindowResize = false; // turn off autosizing
37935 this.layout = config.layout;
37936 this.layout.getEl().addClass("roo-layout-nested-layout");
37937 this.layout.parent = this;
37944 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37946 setSize : function(width, height){
37947 if(!this.ignoreResize(width, height)){
37948 var size = this.adjustForComponents(width, height);
37949 var el = this.layout.getEl();
37950 if (size.height < 1) {
37951 el.setWidth(size.width);
37953 el.setSize(size.width, size.height);
37955 var touch = el.dom.offsetWidth;
37956 this.layout.layout();
37957 // ie requires a double layout on the first pass
37958 if(Roo.isIE && !this.initialized){
37959 this.initialized = true;
37960 this.layout.layout();
37965 // activate all subpanels if not currently active..
37967 setActiveState : function(active){
37968 this.active = active;
37969 this.setActiveClass(active);
37972 this.fireEvent("deactivate", this);
37976 this.fireEvent("activate", this);
37977 // not sure if this should happen before or after..
37978 if (!this.layout) {
37979 return; // should not happen..
37982 for (var r in this.layout.regions) {
37983 reg = this.layout.getRegion(r);
37984 if (reg.getActivePanel()) {
37985 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37986 reg.setActivePanel(reg.getActivePanel());
37989 if (!reg.panels.length) {
37992 reg.showPanel(reg.getPanel(0));
38001 * Returns the nested BorderLayout for this panel
38002 * @return {Roo.BorderLayout}
38004 getLayout : function(){
38005 return this.layout;
38009 * Adds a xtype elements to the layout of the nested panel
38013 xtype : 'ContentPanel',
38020 xtype : 'NestedLayoutPanel',
38026 items : [ ... list of content panels or nested layout panels.. ]
38030 * @param {Object} cfg Xtype definition of item to add.
38032 addxtype : function(cfg) {
38033 return this.layout.addxtype(cfg);
38038 * Ext JS Library 1.1.1
38039 * Copyright(c) 2006-2007, Ext JS, LLC.
38041 * Originally Released Under LGPL - original licence link has changed is not relivant.
38044 * <script type="text/javascript">
38047 * @class Roo.TabPanel
38048 * @extends Roo.util.Observable
38049 * A lightweight tab container.
38053 // basic tabs 1, built from existing content
38054 var tabs = new Roo.TabPanel("tabs1");
38055 tabs.addTab("script", "View Script");
38056 tabs.addTab("markup", "View Markup");
38057 tabs.activate("script");
38059 // more advanced tabs, built from javascript
38060 var jtabs = new Roo.TabPanel("jtabs");
38061 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38063 // set up the UpdateManager
38064 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38065 var updater = tab2.getUpdateManager();
38066 updater.setDefaultUrl("ajax1.htm");
38067 tab2.on('activate', updater.refresh, updater, true);
38069 // Use setUrl for Ajax loading
38070 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38071 tab3.setUrl("ajax2.htm", null, true);
38074 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38077 jtabs.activate("jtabs-1");
38080 * Create a new TabPanel.
38081 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38082 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38084 Roo.bootstrap.panel.Tabs = function(config){
38086 * The container element for this TabPanel.
38087 * @type Roo.Element
38089 this.el = Roo.get(config.el);
38092 if(typeof config == "boolean"){
38093 this.tabPosition = config ? "bottom" : "top";
38095 Roo.apply(this, config);
38099 if(this.tabPosition == "bottom"){
38100 // if tabs are at the bottom = create the body first.
38101 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38102 this.el.addClass("roo-tabs-bottom");
38104 // next create the tabs holders
38106 if (this.tabPosition == "west"){
38108 var reg = this.region; // fake it..
38110 if (!reg.mgr.parent) {
38113 reg = reg.mgr.parent.region;
38115 Roo.log("got nest?");
38117 if (reg.mgr.getRegion('west')) {
38118 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38119 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38120 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38121 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38122 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38130 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38131 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38132 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38133 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38138 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38141 // finally - if tabs are at the top, then create the body last..
38142 if(this.tabPosition != "bottom"){
38143 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38144 * @type Roo.Element
38146 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38147 this.el.addClass("roo-tabs-top");
38151 this.bodyEl.setStyle("position", "relative");
38153 this.active = null;
38154 this.activateDelegate = this.activate.createDelegate(this);
38159 * Fires when the active tab changes
38160 * @param {Roo.TabPanel} this
38161 * @param {Roo.TabPanelItem} activePanel The new active tab
38165 * @event beforetabchange
38166 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38167 * @param {Roo.TabPanel} this
38168 * @param {Object} e Set cancel to true on this object to cancel the tab change
38169 * @param {Roo.TabPanelItem} tab The tab being changed to
38171 "beforetabchange" : true
38174 Roo.EventManager.onWindowResize(this.onResize, this);
38175 this.cpad = this.el.getPadding("lr");
38176 this.hiddenCount = 0;
38179 // toolbar on the tabbar support...
38180 if (this.toolbar) {
38181 alert("no toolbar support yet");
38182 this.toolbar = false;
38184 var tcfg = this.toolbar;
38185 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38186 this.toolbar = new Roo.Toolbar(tcfg);
38187 if (Roo.isSafari) {
38188 var tbl = tcfg.container.child('table', true);
38189 tbl.setAttribute('width', '100%');
38197 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38200 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38202 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38204 tabPosition : "top",
38206 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38208 currentTabWidth : 0,
38210 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38214 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38218 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38220 preferredTabWidth : 175,
38222 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38224 resizeTabs : false,
38226 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38228 monitorResize : true,
38230 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38232 toolbar : false, // set by caller..
38234 region : false, /// set by caller
38236 disableTooltips : true, // not used yet...
38239 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38240 * @param {String} id The id of the div to use <b>or create</b>
38241 * @param {String} text The text for the tab
38242 * @param {String} content (optional) Content to put in the TabPanelItem body
38243 * @param {Boolean} closable (optional) True to create a close icon on the tab
38244 * @return {Roo.TabPanelItem} The created TabPanelItem
38246 addTab : function(id, text, content, closable, tpl)
38248 var item = new Roo.bootstrap.panel.TabItem({
38252 closable : closable,
38255 this.addTabItem(item);
38257 item.setContent(content);
38263 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38264 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38265 * @return {Roo.TabPanelItem}
38267 getTab : function(id){
38268 return this.items[id];
38272 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38273 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38275 hideTab : function(id){
38276 var t = this.items[id];
38279 this.hiddenCount++;
38280 this.autoSizeTabs();
38285 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38286 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38288 unhideTab : function(id){
38289 var t = this.items[id];
38291 t.setHidden(false);
38292 this.hiddenCount--;
38293 this.autoSizeTabs();
38298 * Adds an existing {@link Roo.TabPanelItem}.
38299 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38301 addTabItem : function(item)
38303 this.items[item.id] = item;
38304 this.items.push(item);
38305 this.autoSizeTabs();
38306 // if(this.resizeTabs){
38307 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38308 // this.autoSizeTabs();
38310 // item.autoSize();
38315 * Removes a {@link Roo.TabPanelItem}.
38316 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38318 removeTab : function(id){
38319 var items = this.items;
38320 var tab = items[id];
38321 if(!tab) { return; }
38322 var index = items.indexOf(tab);
38323 if(this.active == tab && items.length > 1){
38324 var newTab = this.getNextAvailable(index);
38329 this.stripEl.dom.removeChild(tab.pnode.dom);
38330 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38331 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38333 items.splice(index, 1);
38334 delete this.items[tab.id];
38335 tab.fireEvent("close", tab);
38336 tab.purgeListeners();
38337 this.autoSizeTabs();
38340 getNextAvailable : function(start){
38341 var items = this.items;
38343 // look for a next tab that will slide over to
38344 // replace the one being removed
38345 while(index < items.length){
38346 var item = items[++index];
38347 if(item && !item.isHidden()){
38351 // if one isn't found select the previous tab (on the left)
38354 var item = items[--index];
38355 if(item && !item.isHidden()){
38363 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38364 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38366 disableTab : function(id){
38367 var tab = this.items[id];
38368 if(tab && this.active != tab){
38374 * Enables a {@link Roo.TabPanelItem} that is disabled.
38375 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38377 enableTab : function(id){
38378 var tab = this.items[id];
38383 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38384 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38385 * @return {Roo.TabPanelItem} The TabPanelItem.
38387 activate : function(id)
38389 //Roo.log('activite:' + id);
38391 var tab = this.items[id];
38395 if(tab == this.active || tab.disabled){
38399 this.fireEvent("beforetabchange", this, e, tab);
38400 if(e.cancel !== true && !tab.disabled){
38402 this.active.hide();
38404 this.active = this.items[id];
38405 this.active.show();
38406 this.fireEvent("tabchange", this, this.active);
38412 * Gets the active {@link Roo.TabPanelItem}.
38413 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38415 getActiveTab : function(){
38416 return this.active;
38420 * Updates the tab body element to fit the height of the container element
38421 * for overflow scrolling
38422 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38424 syncHeight : function(targetHeight){
38425 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38426 var bm = this.bodyEl.getMargins();
38427 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38428 this.bodyEl.setHeight(newHeight);
38432 onResize : function(){
38433 if(this.monitorResize){
38434 this.autoSizeTabs();
38439 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38441 beginUpdate : function(){
38442 this.updating = true;
38446 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38448 endUpdate : function(){
38449 this.updating = false;
38450 this.autoSizeTabs();
38454 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38456 autoSizeTabs : function()
38458 var count = this.items.length;
38459 var vcount = count - this.hiddenCount;
38462 this.stripEl.hide();
38464 this.stripEl.show();
38467 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38472 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38473 var availWidth = Math.floor(w / vcount);
38474 var b = this.stripBody;
38475 if(b.getWidth() > w){
38476 var tabs = this.items;
38477 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38478 if(availWidth < this.minTabWidth){
38479 /*if(!this.sleft){ // incomplete scrolling code
38480 this.createScrollButtons();
38483 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38486 if(this.currentTabWidth < this.preferredTabWidth){
38487 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38493 * Returns the number of tabs in this TabPanel.
38496 getCount : function(){
38497 return this.items.length;
38501 * Resizes all the tabs to the passed width
38502 * @param {Number} The new width
38504 setTabWidth : function(width){
38505 this.currentTabWidth = width;
38506 for(var i = 0, len = this.items.length; i < len; i++) {
38507 if(!this.items[i].isHidden()) {
38508 this.items[i].setWidth(width);
38514 * Destroys this TabPanel
38515 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38517 destroy : function(removeEl){
38518 Roo.EventManager.removeResizeListener(this.onResize, this);
38519 for(var i = 0, len = this.items.length; i < len; i++){
38520 this.items[i].purgeListeners();
38522 if(removeEl === true){
38523 this.el.update("");
38528 createStrip : function(container)
38530 var strip = document.createElement("nav");
38531 strip.className = Roo.bootstrap.version == 4 ?
38532 "navbar-light bg-light" :
38533 "navbar navbar-default"; //"x-tabs-wrap";
38534 container.appendChild(strip);
38538 createStripList : function(strip)
38540 // div wrapper for retard IE
38541 // returns the "tr" element.
38542 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38543 //'<div class="x-tabs-strip-wrap">'+
38544 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38545 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38546 return strip.firstChild; //.firstChild.firstChild.firstChild;
38548 createBody : function(container)
38550 var body = document.createElement("div");
38551 Roo.id(body, "tab-body");
38552 //Roo.fly(body).addClass("x-tabs-body");
38553 Roo.fly(body).addClass("tab-content");
38554 container.appendChild(body);
38557 createItemBody :function(bodyEl, id){
38558 var body = Roo.getDom(id);
38560 body = document.createElement("div");
38563 //Roo.fly(body).addClass("x-tabs-item-body");
38564 Roo.fly(body).addClass("tab-pane");
38565 bodyEl.insertBefore(body, bodyEl.firstChild);
38569 createStripElements : function(stripEl, text, closable, tpl)
38571 var td = document.createElement("li"); // was td..
38572 td.className = 'nav-item';
38574 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38577 stripEl.appendChild(td);
38579 td.className = "x-tabs-closable";
38580 if(!this.closeTpl){
38581 this.closeTpl = new Roo.Template(
38582 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38583 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38584 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38587 var el = this.closeTpl.overwrite(td, {"text": text});
38588 var close = el.getElementsByTagName("div")[0];
38589 var inner = el.getElementsByTagName("em")[0];
38590 return {"el": el, "close": close, "inner": inner};
38593 // not sure what this is..
38594 // if(!this.tabTpl){
38595 //this.tabTpl = new Roo.Template(
38596 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38597 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38599 // this.tabTpl = new Roo.Template(
38600 // '<a href="#">' +
38601 // '<span unselectable="on"' +
38602 // (this.disableTooltips ? '' : ' title="{text}"') +
38603 // ' >{text}</span></a>'
38609 var template = tpl || this.tabTpl || false;
38612 template = new Roo.Template(
38613 Roo.bootstrap.version == 4 ?
38615 '<a class="nav-link" href="#" unselectable="on"' +
38616 (this.disableTooltips ? '' : ' title="{text}"') +
38619 '<a class="nav-link" href="#">' +
38620 '<span unselectable="on"' +
38621 (this.disableTooltips ? '' : ' title="{text}"') +
38622 ' >{text}</span></a>'
38627 switch (typeof(template)) {
38631 template = new Roo.Template(template);
38637 var el = template.overwrite(td, {"text": text});
38639 var inner = el.getElementsByTagName("span")[0];
38641 return {"el": el, "inner": inner};
38649 * @class Roo.TabPanelItem
38650 * @extends Roo.util.Observable
38651 * Represents an individual item (tab plus body) in a TabPanel.
38652 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38653 * @param {String} id The id of this TabPanelItem
38654 * @param {String} text The text for the tab of this TabPanelItem
38655 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38657 Roo.bootstrap.panel.TabItem = function(config){
38659 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38660 * @type Roo.TabPanel
38662 this.tabPanel = config.panel;
38664 * The id for this TabPanelItem
38667 this.id = config.id;
38669 this.disabled = false;
38671 this.text = config.text;
38673 this.loaded = false;
38674 this.closable = config.closable;
38677 * The body element for this TabPanelItem.
38678 * @type Roo.Element
38680 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38681 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38682 this.bodyEl.setStyle("display", "block");
38683 this.bodyEl.setStyle("zoom", "1");
38684 //this.hideAction();
38686 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38688 this.el = Roo.get(els.el);
38689 this.inner = Roo.get(els.inner, true);
38690 this.textEl = Roo.bootstrap.version == 4 ?
38691 this.el : Roo.get(this.el.dom.firstChild, true);
38693 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38694 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38697 // this.el.on("mousedown", this.onTabMouseDown, this);
38698 this.el.on("click", this.onTabClick, this);
38700 if(config.closable){
38701 var c = Roo.get(els.close, true);
38702 c.dom.title = this.closeText;
38703 c.addClassOnOver("close-over");
38704 c.on("click", this.closeClick, this);
38710 * Fires when this tab becomes the active tab.
38711 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38712 * @param {Roo.TabPanelItem} this
38716 * @event beforeclose
38717 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38718 * @param {Roo.TabPanelItem} this
38719 * @param {Object} e Set cancel to true on this object to cancel the close.
38721 "beforeclose": true,
38724 * Fires when this tab is closed.
38725 * @param {Roo.TabPanelItem} this
38729 * @event deactivate
38730 * Fires when this tab is no longer the active tab.
38731 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38732 * @param {Roo.TabPanelItem} this
38734 "deactivate" : true
38736 this.hidden = false;
38738 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38741 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38743 purgeListeners : function(){
38744 Roo.util.Observable.prototype.purgeListeners.call(this);
38745 this.el.removeAllListeners();
38748 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38751 this.status_node.addClass("active");
38754 this.tabPanel.stripWrap.repaint();
38756 this.fireEvent("activate", this.tabPanel, this);
38760 * Returns true if this tab is the active tab.
38761 * @return {Boolean}
38763 isActive : function(){
38764 return this.tabPanel.getActiveTab() == this;
38768 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38771 this.status_node.removeClass("active");
38773 this.fireEvent("deactivate", this.tabPanel, this);
38776 hideAction : function(){
38777 this.bodyEl.hide();
38778 this.bodyEl.setStyle("position", "absolute");
38779 this.bodyEl.setLeft("-20000px");
38780 this.bodyEl.setTop("-20000px");
38783 showAction : function(){
38784 this.bodyEl.setStyle("position", "relative");
38785 this.bodyEl.setTop("");
38786 this.bodyEl.setLeft("");
38787 this.bodyEl.show();
38791 * Set the tooltip for the tab.
38792 * @param {String} tooltip The tab's tooltip
38794 setTooltip : function(text){
38795 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38796 this.textEl.dom.qtip = text;
38797 this.textEl.dom.removeAttribute('title');
38799 this.textEl.dom.title = text;
38803 onTabClick : function(e){
38804 e.preventDefault();
38805 this.tabPanel.activate(this.id);
38808 onTabMouseDown : function(e){
38809 e.preventDefault();
38810 this.tabPanel.activate(this.id);
38813 getWidth : function(){
38814 return this.inner.getWidth();
38817 setWidth : function(width){
38818 var iwidth = width - this.linode.getPadding("lr");
38819 this.inner.setWidth(iwidth);
38820 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38821 this.linode.setWidth(width);
38825 * Show or hide the tab
38826 * @param {Boolean} hidden True to hide or false to show.
38828 setHidden : function(hidden){
38829 this.hidden = hidden;
38830 this.linode.setStyle("display", hidden ? "none" : "");
38834 * Returns true if this tab is "hidden"
38835 * @return {Boolean}
38837 isHidden : function(){
38838 return this.hidden;
38842 * Returns the text for this tab
38845 getText : function(){
38849 autoSize : function(){
38850 //this.el.beginMeasure();
38851 this.textEl.setWidth(1);
38853 * #2804 [new] Tabs in Roojs
38854 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38856 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38857 //this.el.endMeasure();
38861 * Sets the text for the tab (Note: this also sets the tooltip text)
38862 * @param {String} text The tab's text and tooltip
38864 setText : function(text){
38866 this.textEl.update(text);
38867 this.setTooltip(text);
38868 //if(!this.tabPanel.resizeTabs){
38869 // this.autoSize();
38873 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38875 activate : function(){
38876 this.tabPanel.activate(this.id);
38880 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38882 disable : function(){
38883 if(this.tabPanel.active != this){
38884 this.disabled = true;
38885 this.status_node.addClass("disabled");
38890 * Enables this TabPanelItem if it was previously disabled.
38892 enable : function(){
38893 this.disabled = false;
38894 this.status_node.removeClass("disabled");
38898 * Sets the content for this TabPanelItem.
38899 * @param {String} content The content
38900 * @param {Boolean} loadScripts true to look for and load scripts
38902 setContent : function(content, loadScripts){
38903 this.bodyEl.update(content, loadScripts);
38907 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38908 * @return {Roo.UpdateManager} The UpdateManager
38910 getUpdateManager : function(){
38911 return this.bodyEl.getUpdateManager();
38915 * Set a URL to be used to load the content for this TabPanelItem.
38916 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38917 * @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)
38918 * @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)
38919 * @return {Roo.UpdateManager} The UpdateManager
38921 setUrl : function(url, params, loadOnce){
38922 if(this.refreshDelegate){
38923 this.un('activate', this.refreshDelegate);
38925 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38926 this.on("activate", this.refreshDelegate);
38927 return this.bodyEl.getUpdateManager();
38931 _handleRefresh : function(url, params, loadOnce){
38932 if(!loadOnce || !this.loaded){
38933 var updater = this.bodyEl.getUpdateManager();
38934 updater.update(url, params, this._setLoaded.createDelegate(this));
38939 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38940 * Will fail silently if the setUrl method has not been called.
38941 * This does not activate the panel, just updates its content.
38943 refresh : function(){
38944 if(this.refreshDelegate){
38945 this.loaded = false;
38946 this.refreshDelegate();
38951 _setLoaded : function(){
38952 this.loaded = true;
38956 closeClick : function(e){
38959 this.fireEvent("beforeclose", this, o);
38960 if(o.cancel !== true){
38961 this.tabPanel.removeTab(this.id);
38965 * The text displayed in the tooltip for the close icon.
38968 closeText : "Close this tab"
38971 * This script refer to:
38972 * Title: International Telephone Input
38973 * Author: Jack O'Connor
38974 * Code version: v12.1.12
38975 * Availability: https://github.com/jackocnr/intl-tel-input.git
38978 Roo.bootstrap.PhoneInputData = function() {
38981 "Afghanistan (افغانستان)",
38986 "Albania (Shqipëri)",
38991 "Algeria (الجزائر)",
39016 "Antigua and Barbuda",
39026 "Armenia (Հայաստան)",
39042 "Austria (Österreich)",
39047 "Azerbaijan (Azərbaycan)",
39057 "Bahrain (البحرين)",
39062 "Bangladesh (বাংলাদেশ)",
39072 "Belarus (Беларусь)",
39077 "Belgium (België)",
39107 "Bosnia and Herzegovina (Босна и Херцеговина)",
39122 "British Indian Ocean Territory",
39127 "British Virgin Islands",
39137 "Bulgaria (България)",
39147 "Burundi (Uburundi)",
39152 "Cambodia (កម្ពុជា)",
39157 "Cameroon (Cameroun)",
39166 ["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"]
39169 "Cape Verde (Kabu Verdi)",
39174 "Caribbean Netherlands",
39185 "Central African Republic (République centrafricaine)",
39205 "Christmas Island",
39211 "Cocos (Keeling) Islands",
39222 "Comoros (جزر القمر)",
39227 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39232 "Congo (Republic) (Congo-Brazzaville)",
39252 "Croatia (Hrvatska)",
39273 "Czech Republic (Česká republika)",
39278 "Denmark (Danmark)",
39293 "Dominican Republic (República Dominicana)",
39297 ["809", "829", "849"]
39315 "Equatorial Guinea (Guinea Ecuatorial)",
39335 "Falkland Islands (Islas Malvinas)",
39340 "Faroe Islands (Føroyar)",
39361 "French Guiana (Guyane française)",
39366 "French Polynesia (Polynésie française)",
39381 "Georgia (საქართველო)",
39386 "Germany (Deutschland)",
39406 "Greenland (Kalaallit Nunaat)",
39443 "Guinea-Bissau (Guiné Bissau)",
39468 "Hungary (Magyarország)",
39473 "Iceland (Ísland)",
39493 "Iraq (العراق)",
39509 "Israel (ישראל)",
39536 "Jordan (الأردن)",
39541 "Kazakhstan (Казахстан)",
39562 "Kuwait (الكويت)",
39567 "Kyrgyzstan (Кыргызстан)",
39577 "Latvia (Latvija)",
39582 "Lebanon (لبنان)",
39597 "Libya (ليبيا)",
39607 "Lithuania (Lietuva)",
39622 "Macedonia (FYROM) (Македонија)",
39627 "Madagascar (Madagasikara)",
39657 "Marshall Islands",
39667 "Mauritania (موريتانيا)",
39672 "Mauritius (Moris)",
39693 "Moldova (Republica Moldova)",
39703 "Mongolia (Монгол)",
39708 "Montenegro (Crna Gora)",
39718 "Morocco (المغرب)",
39724 "Mozambique (Moçambique)",
39729 "Myanmar (Burma) (မြန်မာ)",
39734 "Namibia (Namibië)",
39749 "Netherlands (Nederland)",
39754 "New Caledonia (Nouvelle-Calédonie)",
39789 "North Korea (조선 민주주의 인민 공화국)",
39794 "Northern Mariana Islands",
39810 "Pakistan (پاکستان)",
39820 "Palestine (فلسطين)",
39830 "Papua New Guinea",
39872 "Réunion (La Réunion)",
39878 "Romania (România)",
39894 "Saint Barthélemy",
39905 "Saint Kitts and Nevis",
39915 "Saint Martin (Saint-Martin (partie française))",
39921 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39926 "Saint Vincent and the Grenadines",
39941 "São Tomé and Príncipe (São Tomé e Príncipe)",
39946 "Saudi Arabia (المملكة العربية السعودية)",
39951 "Senegal (Sénégal)",
39981 "Slovakia (Slovensko)",
39986 "Slovenia (Slovenija)",
39996 "Somalia (Soomaaliya)",
40006 "South Korea (대한민국)",
40011 "South Sudan (جنوب السودان)",
40021 "Sri Lanka (ශ්රී ලංකාව)",
40026 "Sudan (السودان)",
40036 "Svalbard and Jan Mayen",
40047 "Sweden (Sverige)",
40052 "Switzerland (Schweiz)",
40057 "Syria (سوريا)",
40102 "Trinidad and Tobago",
40107 "Tunisia (تونس)",
40112 "Turkey (Türkiye)",
40122 "Turks and Caicos Islands",
40132 "U.S. Virgin Islands",
40142 "Ukraine (Україна)",
40147 "United Arab Emirates (الإمارات العربية المتحدة)",
40169 "Uzbekistan (Oʻzbekiston)",
40179 "Vatican City (Città del Vaticano)",
40190 "Vietnam (Việt Nam)",
40195 "Wallis and Futuna (Wallis-et-Futuna)",
40200 "Western Sahara (الصحراء الغربية)",
40206 "Yemen (اليمن)",
40230 * This script refer to:
40231 * Title: International Telephone Input
40232 * Author: Jack O'Connor
40233 * Code version: v12.1.12
40234 * Availability: https://github.com/jackocnr/intl-tel-input.git
40238 * @class Roo.bootstrap.PhoneInput
40239 * @extends Roo.bootstrap.TriggerField
40240 * An input with International dial-code selection
40242 * @cfg {String} defaultDialCode default '+852'
40243 * @cfg {Array} preferedCountries default []
40246 * Create a new PhoneInput.
40247 * @param {Object} config Configuration options
40250 Roo.bootstrap.PhoneInput = function(config) {
40251 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40254 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40256 listWidth: undefined,
40258 selectedClass: 'active',
40260 invalidClass : "has-warning",
40262 validClass: 'has-success',
40264 allowed: '0123456789',
40269 * @cfg {String} defaultDialCode The default dial code when initializing the input
40271 defaultDialCode: '+852',
40274 * @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
40276 preferedCountries: false,
40278 getAutoCreate : function()
40280 var data = Roo.bootstrap.PhoneInputData();
40281 var align = this.labelAlign || this.parentLabelAlign();
40284 this.allCountries = [];
40285 this.dialCodeMapping = [];
40287 for (var i = 0; i < data.length; i++) {
40289 this.allCountries[i] = {
40293 priority: c[3] || 0,
40294 areaCodes: c[4] || null
40296 this.dialCodeMapping[c[2]] = {
40299 priority: c[3] || 0,
40300 areaCodes: c[4] || null
40312 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40313 maxlength: this.max_length,
40314 cls : 'form-control tel-input',
40315 autocomplete: 'new-password'
40318 var hiddenInput = {
40321 cls: 'hidden-tel-input'
40325 hiddenInput.name = this.name;
40328 if (this.disabled) {
40329 input.disabled = true;
40332 var flag_container = {
40349 cls: this.hasFeedback ? 'has-feedback' : '',
40355 cls: 'dial-code-holder',
40362 cls: 'roo-select2-container input-group',
40369 if (this.fieldLabel.length) {
40372 tooltip: 'This field is required'
40378 cls: 'control-label',
40384 html: this.fieldLabel
40387 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40393 if(this.indicatorpos == 'right') {
40394 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40401 if(align == 'left') {
40409 if(this.labelWidth > 12){
40410 label.style = "width: " + this.labelWidth + 'px';
40412 if(this.labelWidth < 13 && this.labelmd == 0){
40413 this.labelmd = this.labelWidth;
40415 if(this.labellg > 0){
40416 label.cls += ' col-lg-' + this.labellg;
40417 input.cls += ' col-lg-' + (12 - this.labellg);
40419 if(this.labelmd > 0){
40420 label.cls += ' col-md-' + this.labelmd;
40421 container.cls += ' col-md-' + (12 - this.labelmd);
40423 if(this.labelsm > 0){
40424 label.cls += ' col-sm-' + this.labelsm;
40425 container.cls += ' col-sm-' + (12 - this.labelsm);
40427 if(this.labelxs > 0){
40428 label.cls += ' col-xs-' + this.labelxs;
40429 container.cls += ' col-xs-' + (12 - this.labelxs);
40439 var settings = this;
40441 ['xs','sm','md','lg'].map(function(size){
40442 if (settings[size]) {
40443 cfg.cls += ' col-' + size + '-' + settings[size];
40447 this.store = new Roo.data.Store({
40448 proxy : new Roo.data.MemoryProxy({}),
40449 reader : new Roo.data.JsonReader({
40460 'name' : 'dialCode',
40464 'name' : 'priority',
40468 'name' : 'areaCodes',
40475 if(!this.preferedCountries) {
40476 this.preferedCountries = [
40483 var p = this.preferedCountries.reverse();
40486 for (var i = 0; i < p.length; i++) {
40487 for (var j = 0; j < this.allCountries.length; j++) {
40488 if(this.allCountries[j].iso2 == p[i]) {
40489 var t = this.allCountries[j];
40490 this.allCountries.splice(j,1);
40491 this.allCountries.unshift(t);
40497 this.store.proxy.data = {
40499 data: this.allCountries
40505 initEvents : function()
40508 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40510 this.indicator = this.indicatorEl();
40511 this.flag = this.flagEl();
40512 this.dialCodeHolder = this.dialCodeHolderEl();
40514 this.trigger = this.el.select('div.flag-box',true).first();
40515 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40520 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40521 _this.list.setWidth(lw);
40524 this.list.on('mouseover', this.onViewOver, this);
40525 this.list.on('mousemove', this.onViewMove, this);
40526 this.inputEl().on("keyup", this.onKeyUp, this);
40527 this.inputEl().on("keypress", this.onKeyPress, this);
40529 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40531 this.view = new Roo.View(this.list, this.tpl, {
40532 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40535 this.view.on('click', this.onViewClick, this);
40536 this.setValue(this.defaultDialCode);
40539 onTriggerClick : function(e)
40541 Roo.log('trigger click');
40546 if(this.isExpanded()){
40548 this.hasFocus = false;
40550 this.store.load({});
40551 this.hasFocus = true;
40556 isExpanded : function()
40558 return this.list.isVisible();
40561 collapse : function()
40563 if(!this.isExpanded()){
40567 Roo.get(document).un('mousedown', this.collapseIf, this);
40568 Roo.get(document).un('mousewheel', this.collapseIf, this);
40569 this.fireEvent('collapse', this);
40573 expand : function()
40577 if(this.isExpanded() || !this.hasFocus){
40581 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40582 this.list.setWidth(lw);
40585 this.restrictHeight();
40587 Roo.get(document).on('mousedown', this.collapseIf, this);
40588 Roo.get(document).on('mousewheel', this.collapseIf, this);
40590 this.fireEvent('expand', this);
40593 restrictHeight : function()
40595 this.list.alignTo(this.inputEl(), this.listAlign);
40596 this.list.alignTo(this.inputEl(), this.listAlign);
40599 onViewOver : function(e, t)
40601 if(this.inKeyMode){
40604 var item = this.view.findItemFromChild(t);
40607 var index = this.view.indexOf(item);
40608 this.select(index, false);
40613 onViewClick : function(view, doFocus, el, e)
40615 var index = this.view.getSelectedIndexes()[0];
40617 var r = this.store.getAt(index);
40620 this.onSelect(r, index);
40622 if(doFocus !== false && !this.blockFocus){
40623 this.inputEl().focus();
40627 onViewMove : function(e, t)
40629 this.inKeyMode = false;
40632 select : function(index, scrollIntoView)
40634 this.selectedIndex = index;
40635 this.view.select(index);
40636 if(scrollIntoView !== false){
40637 var el = this.view.getNode(index);
40639 this.list.scrollChildIntoView(el, false);
40644 createList : function()
40646 this.list = Roo.get(document.body).createChild({
40648 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40649 style: 'display:none'
40652 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40655 collapseIf : function(e)
40657 var in_combo = e.within(this.el);
40658 var in_list = e.within(this.list);
40659 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40661 if (in_combo || in_list || is_list) {
40667 onSelect : function(record, index)
40669 if(this.fireEvent('beforeselect', this, record, index) !== false){
40671 this.setFlagClass(record.data.iso2);
40672 this.setDialCode(record.data.dialCode);
40673 this.hasFocus = false;
40675 this.fireEvent('select', this, record, index);
40679 flagEl : function()
40681 var flag = this.el.select('div.flag',true).first();
40688 dialCodeHolderEl : function()
40690 var d = this.el.select('input.dial-code-holder',true).first();
40697 setDialCode : function(v)
40699 this.dialCodeHolder.dom.value = '+'+v;
40702 setFlagClass : function(n)
40704 this.flag.dom.className = 'flag '+n;
40707 getValue : function()
40709 var v = this.inputEl().getValue();
40710 if(this.dialCodeHolder) {
40711 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40716 setValue : function(v)
40718 var d = this.getDialCode(v);
40720 //invalid dial code
40721 if(v.length == 0 || !d || d.length == 0) {
40723 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40724 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40730 this.setFlagClass(this.dialCodeMapping[d].iso2);
40731 this.setDialCode(d);
40732 this.inputEl().dom.value = v.replace('+'+d,'');
40733 this.hiddenEl().dom.value = this.getValue();
40738 getDialCode : function(v)
40742 if (v.length == 0) {
40743 return this.dialCodeHolder.dom.value;
40747 if (v.charAt(0) != "+") {
40750 var numericChars = "";
40751 for (var i = 1; i < v.length; i++) {
40752 var c = v.charAt(i);
40755 if (this.dialCodeMapping[numericChars]) {
40756 dialCode = v.substr(1, i);
40758 if (numericChars.length == 4) {
40768 this.setValue(this.defaultDialCode);
40772 hiddenEl : function()
40774 return this.el.select('input.hidden-tel-input',true).first();
40777 // after setting val
40778 onKeyUp : function(e){
40779 this.setValue(this.getValue());
40782 onKeyPress : function(e){
40783 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40790 * @class Roo.bootstrap.MoneyField
40791 * @extends Roo.bootstrap.ComboBox
40792 * Bootstrap MoneyField class
40795 * Create a new MoneyField.
40796 * @param {Object} config Configuration options
40799 Roo.bootstrap.MoneyField = function(config) {
40801 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40805 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40808 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40810 allowDecimals : true,
40812 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40814 decimalSeparator : ".",
40816 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40818 decimalPrecision : 0,
40820 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40822 allowNegative : true,
40824 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40828 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40830 minValue : Number.NEGATIVE_INFINITY,
40832 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40834 maxValue : Number.MAX_VALUE,
40836 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40838 minText : "The minimum value for this field is {0}",
40840 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40842 maxText : "The maximum value for this field is {0}",
40844 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40845 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40847 nanText : "{0} is not a valid number",
40849 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40853 * @cfg {String} defaults currency of the MoneyField
40854 * value should be in lkey
40856 defaultCurrency : false,
40858 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40860 thousandsDelimiter : false,
40862 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40873 getAutoCreate : function()
40875 var align = this.labelAlign || this.parentLabelAlign();
40887 cls : 'form-control roo-money-amount-input',
40888 autocomplete: 'new-password'
40891 var hiddenInput = {
40895 cls: 'hidden-number-input'
40898 if(this.max_length) {
40899 input.maxlength = this.max_length;
40903 hiddenInput.name = this.name;
40906 if (this.disabled) {
40907 input.disabled = true;
40910 var clg = 12 - this.inputlg;
40911 var cmd = 12 - this.inputmd;
40912 var csm = 12 - this.inputsm;
40913 var cxs = 12 - this.inputxs;
40917 cls : 'row roo-money-field',
40921 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40925 cls: 'roo-select2-container input-group',
40929 cls : 'form-control roo-money-currency-input',
40930 autocomplete: 'new-password',
40932 name : this.currencyName
40936 cls : 'input-group-addon',
40950 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40954 cls: this.hasFeedback ? 'has-feedback' : '',
40965 if (this.fieldLabel.length) {
40968 tooltip: 'This field is required'
40974 cls: 'control-label',
40980 html: this.fieldLabel
40983 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40989 if(this.indicatorpos == 'right') {
40990 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40997 if(align == 'left') {
41005 if(this.labelWidth > 12){
41006 label.style = "width: " + this.labelWidth + 'px';
41008 if(this.labelWidth < 13 && this.labelmd == 0){
41009 this.labelmd = this.labelWidth;
41011 if(this.labellg > 0){
41012 label.cls += ' col-lg-' + this.labellg;
41013 input.cls += ' col-lg-' + (12 - this.labellg);
41015 if(this.labelmd > 0){
41016 label.cls += ' col-md-' + this.labelmd;
41017 container.cls += ' col-md-' + (12 - this.labelmd);
41019 if(this.labelsm > 0){
41020 label.cls += ' col-sm-' + this.labelsm;
41021 container.cls += ' col-sm-' + (12 - this.labelsm);
41023 if(this.labelxs > 0){
41024 label.cls += ' col-xs-' + this.labelxs;
41025 container.cls += ' col-xs-' + (12 - this.labelxs);
41036 var settings = this;
41038 ['xs','sm','md','lg'].map(function(size){
41039 if (settings[size]) {
41040 cfg.cls += ' col-' + size + '-' + settings[size];
41047 initEvents : function()
41049 this.indicator = this.indicatorEl();
41051 this.initCurrencyEvent();
41053 this.initNumberEvent();
41056 initCurrencyEvent : function()
41059 throw "can not find store for combo";
41062 this.store = Roo.factory(this.store, Roo.data);
41063 this.store.parent = this;
41067 this.triggerEl = this.el.select('.input-group-addon', true).first();
41069 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41074 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41075 _this.list.setWidth(lw);
41078 this.list.on('mouseover', this.onViewOver, this);
41079 this.list.on('mousemove', this.onViewMove, this);
41080 this.list.on('scroll', this.onViewScroll, this);
41083 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41086 this.view = new Roo.View(this.list, this.tpl, {
41087 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41090 this.view.on('click', this.onViewClick, this);
41092 this.store.on('beforeload', this.onBeforeLoad, this);
41093 this.store.on('load', this.onLoad, this);
41094 this.store.on('loadexception', this.onLoadException, this);
41096 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41097 "up" : function(e){
41098 this.inKeyMode = true;
41102 "down" : function(e){
41103 if(!this.isExpanded()){
41104 this.onTriggerClick();
41106 this.inKeyMode = true;
41111 "enter" : function(e){
41114 if(this.fireEvent("specialkey", this, e)){
41115 this.onViewClick(false);
41121 "esc" : function(e){
41125 "tab" : function(e){
41128 if(this.fireEvent("specialkey", this, e)){
41129 this.onViewClick(false);
41137 doRelay : function(foo, bar, hname){
41138 if(hname == 'down' || this.scope.isExpanded()){
41139 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41147 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41151 initNumberEvent : function(e)
41153 this.inputEl().on("keydown" , this.fireKey, this);
41154 this.inputEl().on("focus", this.onFocus, this);
41155 this.inputEl().on("blur", this.onBlur, this);
41157 this.inputEl().relayEvent('keyup', this);
41159 if(this.indicator){
41160 this.indicator.addClass('invisible');
41163 this.originalValue = this.getValue();
41165 if(this.validationEvent == 'keyup'){
41166 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41167 this.inputEl().on('keyup', this.filterValidation, this);
41169 else if(this.validationEvent !== false){
41170 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41173 if(this.selectOnFocus){
41174 this.on("focus", this.preFocus, this);
41177 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41178 this.inputEl().on("keypress", this.filterKeys, this);
41180 this.inputEl().relayEvent('keypress', this);
41183 var allowed = "0123456789";
41185 if(this.allowDecimals){
41186 allowed += this.decimalSeparator;
41189 if(this.allowNegative){
41193 if(this.thousandsDelimiter) {
41197 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41199 var keyPress = function(e){
41201 var k = e.getKey();
41203 var c = e.getCharCode();
41206 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41207 allowed.indexOf(String.fromCharCode(c)) === -1
41213 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41217 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41222 this.inputEl().on("keypress", keyPress, this);
41226 onTriggerClick : function(e)
41233 this.loadNext = false;
41235 if(this.isExpanded()){
41240 this.hasFocus = true;
41242 if(this.triggerAction == 'all') {
41243 this.doQuery(this.allQuery, true);
41247 this.doQuery(this.getRawValue());
41250 getCurrency : function()
41252 var v = this.currencyEl().getValue();
41257 restrictHeight : function()
41259 this.list.alignTo(this.currencyEl(), this.listAlign);
41260 this.list.alignTo(this.currencyEl(), this.listAlign);
41263 onViewClick : function(view, doFocus, el, e)
41265 var index = this.view.getSelectedIndexes()[0];
41267 var r = this.store.getAt(index);
41270 this.onSelect(r, index);
41274 onSelect : function(record, index){
41276 if(this.fireEvent('beforeselect', this, record, index) !== false){
41278 this.setFromCurrencyData(index > -1 ? record.data : false);
41282 this.fireEvent('select', this, record, index);
41286 setFromCurrencyData : function(o)
41290 this.lastCurrency = o;
41292 if (this.currencyField) {
41293 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41295 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41298 this.lastSelectionText = currency;
41300 //setting default currency
41301 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41302 this.setCurrency(this.defaultCurrency);
41306 this.setCurrency(currency);
41309 setFromData : function(o)
41313 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41315 this.setFromCurrencyData(c);
41320 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41322 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41325 this.setValue(value);
41329 setCurrency : function(v)
41331 this.currencyValue = v;
41334 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41339 setValue : function(v)
41341 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41347 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41349 this.inputEl().dom.value = (v == '') ? '' :
41350 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41352 if(!this.allowZero && v === '0') {
41353 this.hiddenEl().dom.value = '';
41354 this.inputEl().dom.value = '';
41361 getRawValue : function()
41363 var v = this.inputEl().getValue();
41368 getValue : function()
41370 return this.fixPrecision(this.parseValue(this.getRawValue()));
41373 parseValue : function(value)
41375 if(this.thousandsDelimiter) {
41377 r = new RegExp(",", "g");
41378 value = value.replace(r, "");
41381 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41382 return isNaN(value) ? '' : value;
41386 fixPrecision : function(value)
41388 if(this.thousandsDelimiter) {
41390 r = new RegExp(",", "g");
41391 value = value.replace(r, "");
41394 var nan = isNaN(value);
41396 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41397 return nan ? '' : value;
41399 return parseFloat(value).toFixed(this.decimalPrecision);
41402 decimalPrecisionFcn : function(v)
41404 return Math.floor(v);
41407 validateValue : function(value)
41409 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41413 var num = this.parseValue(value);
41416 this.markInvalid(String.format(this.nanText, value));
41420 if(num < this.minValue){
41421 this.markInvalid(String.format(this.minText, this.minValue));
41425 if(num > this.maxValue){
41426 this.markInvalid(String.format(this.maxText, this.maxValue));
41433 validate : function()
41435 if(this.disabled || this.allowBlank){
41440 var currency = this.getCurrency();
41442 if(this.validateValue(this.getRawValue()) && currency.length){
41447 this.markInvalid();
41451 getName: function()
41456 beforeBlur : function()
41462 var v = this.parseValue(this.getRawValue());
41469 onBlur : function()
41473 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41474 //this.el.removeClass(this.focusClass);
41477 this.hasFocus = false;
41479 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41483 var v = this.getValue();
41485 if(String(v) !== String(this.startValue)){
41486 this.fireEvent('change', this, v, this.startValue);
41489 this.fireEvent("blur", this);
41492 inputEl : function()
41494 return this.el.select('.roo-money-amount-input', true).first();
41497 currencyEl : function()
41499 return this.el.select('.roo-money-currency-input', true).first();
41502 hiddenEl : function()
41504 return this.el.select('input.hidden-number-input',true).first();
41508 * This script refer to:
41509 * Title: Signature Pad
41511 * Availability: https://github.com/szimek/signature_pad
41515 * @class Roo.bootstrap.BezierSignature
41516 * @extends Roo.bootstrap.Component
41517 * Bootstrap BezierSignature class
41520 * Create a new BezierSignature
41521 * @param {Object} config The config object
41524 Roo.bootstrap.BezierSignature = function(config){
41525 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41531 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component, {
41537 mouse_btn_down: true,
41540 * @cfg(int) canvas height
41542 canvas_height: '200px',
41545 * @cfg(float or function) Radius of a single dot.
41550 * @cfg(float) Minimum width of a line. Defaults to 0.5.
41555 * @cfg(float) Maximum width of a line. Defaults to 2.5.
41560 * @cfg(integer) Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41565 * @cfg(integer) Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41570 * @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.
41572 bg_color: 'rgba(0, 0, 0, 0)',
41575 * @cfg(string) Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41577 dot_color: 'black',
41580 * @cfg(float) Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41582 velocity_filter_weight: 0.7,
41585 * @cfg(function) Callback when stroke begin.
41590 * @cfg(function) Callback when stroke end.
41594 getAutoCreate : function()
41596 var cls = 'roo-signature column';
41599 cls += ' ' + this.cls;
41609 for(var i = 0; i < col_sizes.length; i++) {
41610 if(this[col_sizes[i]]) {
41611 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41621 cls: 'roo-signature-body',
41625 cls: 'roo-signature-body-canvas',
41626 height: this.canvas_height,
41627 width: this.canvas_width
41634 style: 'display: none'
41642 initEvents: function()
41644 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41646 var canvas = this.canvasEl();
41648 // mouse && touch event swapping...
41649 canvas.dom.style.touchAction = 'none';
41650 canvas.dom.style.msTouchAction = 'none';
41652 this.mouse_btn_down = false;
41653 canvas.on('mousedown', this._handleMouseDown, this);
41654 canvas.on('mousemove', this._handleMouseMove, this);
41655 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41657 if (window.PointerEvent) {
41658 canvas.on('pointerdown', this._handleMouseDown, this);
41659 canvas.on('pointermove', this._handleMouseMove, this);
41660 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41663 if ('ontouchstart' in window) {
41664 canvas.on('touchstart', this._handleTouchStart, this);
41665 canvas.on('touchmove', this._handleTouchMove, this);
41666 canvas.on('touchend', this._handleTouchEnd, this);
41669 Roo.EventManager.onWindowResize(this.resize, this, true);
41671 // file input event
41672 this.fileEl().on('change', this.uploadImage, this);
41679 resize: function(){
41681 var canvas = this.canvasEl().dom;
41682 var ctx = this.canvasElCtx();
41683 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41685 // setting canvas width will clean img data
41688 var style = window.getComputedStyle ?
41689 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41691 var padding_left = parseInt(style.paddingLeft) || 0;
41692 var padding_right = parseInt(style.paddingRight) || 0;
41694 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41696 ctx.putImageData(img_data, 0, 0);
41699 _handleMouseDown: function(e)
41701 if (e.browserEvent.which === 1) {
41702 this.mouse_btn_down = true;
41703 this.strokeBegin(e);
41707 _handleMouseMove: function (e)
41709 if (this.mouse_btn_down) {
41710 this.strokeMoveUpdate(e);
41714 _handleMouseUp: function (e)
41716 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41717 this.mouse_btn_down = false;
41722 _handleTouchStart: function (e) {
41724 e.preventDefault();
41725 if (e.browserEvent.targetTouches.length === 1) {
41726 // var touch = e.browserEvent.changedTouches[0];
41727 // this.strokeBegin(touch);
41729 this.strokeBegin(e); // assume e catching the correct xy...
41733 _handleTouchMove: function (e) {
41734 e.preventDefault();
41735 // var touch = event.targetTouches[0];
41736 // _this._strokeMoveUpdate(touch);
41737 this.strokeMoveUpdate(e);
41740 _handleTouchEnd: function (e) {
41741 var wasCanvasTouched = e.target === this.canvasEl().dom;
41742 if (wasCanvasTouched) {
41743 e.preventDefault();
41744 // var touch = event.changedTouches[0];
41745 // _this._strokeEnd(touch);
41750 reset: function () {
41751 this._lastPoints = [];
41752 this._lastVelocity = 0;
41753 this._lastWidth = (this.min_width + this.max_width) / 2;
41754 this.canvasElCtx().fillStyle = this.dot_color;
41757 strokeMoveUpdate: function(e)
41759 this.strokeUpdate(e);
41761 if (this.throttle) {
41762 this.throttle(this.strokeUpdate, this.throttle);
41765 this.strokeUpdate(e);
41769 strokeBegin: function(e)
41771 var newPointGroup = {
41772 color: this.dot_color,
41776 if (typeof this.onBegin === 'function') {
41780 this.curve_data.push(newPointGroup);
41782 this.strokeUpdate(e);
41785 strokeUpdate: function(e)
41787 var rect = this.canvasEl().dom.getBoundingClientRect();
41788 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41789 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41790 var lastPoints = lastPointGroup.points;
41791 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41792 var isLastPointTooClose = lastPoint
41793 ? point.distanceTo(lastPoint) <= this.min_distance
41795 var color = lastPointGroup.color;
41796 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41797 var curve = this.addPoint(point);
41799 this.drawDot({color: color, point: point});
41802 this.drawCurve({color: color, curve: curve});
41812 strokeEnd: function(e)
41814 this.strokeUpdate(e);
41815 if (typeof this.onEnd === 'function') {
41820 addPoint: function (point) {
41821 var _lastPoints = this._lastPoints;
41822 _lastPoints.push(point);
41823 if (_lastPoints.length > 2) {
41824 if (_lastPoints.length === 3) {
41825 _lastPoints.unshift(_lastPoints[0]);
41827 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41828 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41829 _lastPoints.shift();
41835 calculateCurveWidths: function (startPoint, endPoint) {
41836 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41837 (1 - this.velocity_filter_weight) * this._lastVelocity;
41839 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41842 start: this._lastWidth
41845 this._lastVelocity = velocity;
41846 this._lastWidth = newWidth;
41850 drawDot: function (_a) {
41851 var color = _a.color, point = _a.point;
41852 var ctx = this.canvasElCtx();
41853 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41855 this.drawCurveSegment(point.x, point.y, width);
41857 ctx.fillStyle = color;
41861 drawCurve: function (_a) {
41862 var color = _a.color, curve = _a.curve;
41863 var ctx = this.canvasElCtx();
41864 var widthDelta = curve.endWidth - curve.startWidth;
41865 var drawSteps = Math.floor(curve.length()) * 2;
41867 ctx.fillStyle = color;
41868 for (var i = 0; i < drawSteps; i += 1) {
41869 var t = i / drawSteps;
41875 var x = uuu * curve.startPoint.x;
41876 x += 3 * uu * t * curve.control1.x;
41877 x += 3 * u * tt * curve.control2.x;
41878 x += ttt * curve.endPoint.x;
41879 var y = uuu * curve.startPoint.y;
41880 y += 3 * uu * t * curve.control1.y;
41881 y += 3 * u * tt * curve.control2.y;
41882 y += ttt * curve.endPoint.y;
41883 var width = curve.startWidth + ttt * widthDelta;
41884 this.drawCurveSegment(x, y, width);
41890 drawCurveSegment: function (x, y, width) {
41891 var ctx = this.canvasElCtx();
41893 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
41894 this.is_empty = false;
41899 var ctx = this.canvasElCtx();
41900 var canvas = this.canvasEl().dom;
41901 ctx.fillStyle = this.bg_color;
41902 ctx.clearRect(0, 0, canvas.width, canvas.height);
41903 ctx.fillRect(0, 0, canvas.width, canvas.height);
41904 this.curve_data = [];
41906 this.is_empty = true;
41911 return this.el.select('input',true).first();
41914 canvasEl: function()
41916 return this.el.select('canvas',true).first();
41919 canvasElCtx: function()
41921 return this.el.select('canvas',true).first().dom.getContext('2d');
41924 getImage: function(type)
41926 if(this.is_empty) {
41931 return this.canvasEl().dom.toDataURL('image/'+type, 1);
41934 drawFromImage: function(img_src)
41936 var img = new Image();
41938 img.onload = function(){
41939 this.canvasElCtx().drawImage(img, 0, 0);
41944 this.is_empty = false;
41947 selectImage: function()
41949 this.fileEl().dom.click();
41952 uploadImage: function(e)
41954 var reader = new FileReader();
41956 reader.onload = function(e){
41957 var img = new Image();
41958 img.onload = function(){
41960 this.canvasElCtx().drawImage(img, 0, 0);
41962 img.src = e.target.result;
41965 reader.readAsDataURL(e.target.files[0]);
41968 // Bezier Point Constructor
41969 Point: (function () {
41970 function Point(x, y, time) {
41973 this.time = time || Date.now();
41975 Point.prototype.distanceTo = function (start) {
41976 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
41978 Point.prototype.equals = function (other) {
41979 return this.x === other.x && this.y === other.y && this.time === other.time;
41981 Point.prototype.velocityFrom = function (start) {
41982 return this.time !== start.time
41983 ? this.distanceTo(start) / (this.time - start.time)
41990 // Bezier Constructor
41991 Bezier: (function () {
41992 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
41993 this.startPoint = startPoint;
41994 this.control2 = control2;
41995 this.control1 = control1;
41996 this.endPoint = endPoint;
41997 this.startWidth = startWidth;
41998 this.endWidth = endWidth;
42000 Bezier.fromPoints = function (points, widths, scope) {
42001 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
42002 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
42003 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42005 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42006 var dx1 = s1.x - s2.x;
42007 var dy1 = s1.y - s2.y;
42008 var dx2 = s2.x - s3.x;
42009 var dy2 = s2.y - s3.y;
42010 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42011 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42012 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42013 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42014 var dxm = m1.x - m2.x;
42015 var dym = m1.y - m2.y;
42016 var k = l2 / (l1 + l2);
42017 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42018 var tx = s2.x - cm.x;
42019 var ty = s2.y - cm.y;
42021 c1: new scope.Point(m1.x + tx, m1.y + ty),
42022 c2: new scope.Point(m2.x + tx, m2.y + ty)
42025 Bezier.prototype.length = function () {
42030 for (var i = 0; i <= steps; i += 1) {
42032 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42033 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42035 var xdiff = cx - px;
42036 var ydiff = cy - py;
42037 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42044 Bezier.prototype.point = function (t, start, c1, c2, end) {
42045 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42046 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42047 + (3.0 * c2 * (1.0 - t) * t * t)
42048 + (end * t * t * t);
42053 throttle: function(fn, wait) {
42054 if (wait === void 0) { wait = 250; }
42056 var timeout = null;
42060 var later = function () {
42061 previous = Date.now();
42063 result = fn.apply(storedContext, storedArgs);
42065 storedContext = null;
42069 return function wrapper() {
42071 for (var _i = 0; _i < arguments.length; _i++) {
42072 args[_i] = arguments[_i];
42074 var now = Date.now();
42075 var remaining = wait - (now - previous);
42076 storedContext = this;
42078 if (remaining <= 0 || remaining > wait) {
42080 clearTimeout(timeout);
42084 result = fn.apply(storedContext, storedArgs);
42086 storedContext = null;
42090 else if (!timeout) {
42091 timeout = window.setTimeout(later, remaining);