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');
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass('hidden');
433 this.fireEvent('hide', this);
446 * @class Roo.bootstrap.Body
447 * @extends Roo.bootstrap.Component
448 * Bootstrap Body class
452 * @param {Object} config The config object
455 Roo.bootstrap.Body = function(config){
457 config = config || {};
459 Roo.bootstrap.Body.superclass.constructor.call(this, config);
460 this.el = Roo.get(config.el ? config.el : document.body );
461 if (this.cls && this.cls.length) {
462 Roo.get(document.body).addClass(this.cls);
466 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
468 is_body : true,// just to make sure it's constructed?
473 onRender : function(ct, position)
475 /* Roo.log("Roo.bootstrap.Body - onRender");
476 if (this.cls && this.cls.length) {
477 Roo.get(document.body).addClass(this.cls);
496 * @class Roo.bootstrap.ButtonGroup
497 * @extends Roo.bootstrap.Component
498 * Bootstrap ButtonGroup class
499 * @cfg {String} size lg | sm | xs (default empty normal)
500 * @cfg {String} align vertical | justified (default none)
501 * @cfg {String} direction up | down (default down)
502 * @cfg {Boolean} toolbar false | true
503 * @cfg {Boolean} btn true | false
508 * @param {Object} config The config object
511 Roo.bootstrap.ButtonGroup = function(config){
512 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
515 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
523 getAutoCreate : function(){
529 cfg.html = this.html || cfg.html;
540 if (['vertical','justified'].indexOf(this.align)!==-1) {
541 cfg.cls = 'btn-group-' + this.align;
543 if (this.align == 'justified') {
544 console.log(this.items);
548 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
549 cfg.cls += ' btn-group-' + this.size;
552 if (this.direction == 'up') {
553 cfg.cls += ' dropup' ;
559 * Add a button to the group (similar to NavItem API.)
561 addItem : function(cfg)
563 var cn = new Roo.bootstrap.Button(cfg);
565 cn.parentId = this.id;
566 cn.onRender(this.el, null);
580 * @class Roo.bootstrap.Button
581 * @extends Roo.bootstrap.Component
582 * Bootstrap Button class
583 * @cfg {String} html The button content
584 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
585 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
586 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
587 * @cfg {String} size ( lg | sm | xs)
588 * @cfg {String} tag ( a | input | submit)
589 * @cfg {String} href empty or href
590 * @cfg {Boolean} disabled default false;
591 * @cfg {Boolean} isClose default false;
592 * @cfg {String} glyphicon depricated - use fa
593 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
594 * @cfg {String} badge text for badge
595 * @cfg {String} theme (default|glow)
596 * @cfg {Boolean} inverse dark themed version
597 * @cfg {Boolean} toggle is it a slidy toggle button
598 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
599 * @cfg {String} ontext text for on slidy toggle state
600 * @cfg {String} offtext text for off slidy toggle state
601 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
602 * @cfg {Boolean} removeClass remove the standard class..
603 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
606 * Create a new button
607 * @param {Object} config The config object
611 Roo.bootstrap.Button = function(config){
612 Roo.bootstrap.Button.superclass.constructor.call(this, config);
613 this.weightClass = ["btn-default btn-outline-secondary",
625 * When a butotn is pressed
626 * @param {Roo.bootstrap.Button} btn
627 * @param {Roo.EventObject} e
632 * After the button has been toggles
633 * @param {Roo.bootstrap.Button} btn
634 * @param {Roo.EventObject} e
635 * @param {boolean} pressed (also available as button.pressed)
641 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
662 preventDefault: true,
670 getAutoCreate : function(){
678 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
679 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
684 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
686 if (this.toggle == true) {
689 cls: 'slider-frame roo-button',
694 'data-off-text':'OFF',
695 cls: 'slider-button',
701 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
702 cfg.cls += ' '+this.weight;
711 cfg["aria-hidden"] = true;
713 cfg.html = "×";
719 if (this.theme==='default') {
720 cfg.cls = 'btn roo-button';
722 //if (this.parentType != 'Navbar') {
723 this.weight = this.weight.length ? this.weight : 'default';
725 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
727 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
728 var weight = this.weight == 'default' ? 'secondary' : this.weight;
729 cfg.cls += ' btn-' + outline + weight;
730 if (this.weight == 'default') {
732 cfg.cls += ' btn-' + this.weight;
735 } else if (this.theme==='glow') {
738 cfg.cls = 'btn-glow roo-button';
740 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
742 cfg.cls += ' ' + this.weight;
748 this.cls += ' inverse';
752 if (this.active || this.pressed === true) {
753 cfg.cls += ' active';
757 cfg.disabled = 'disabled';
761 Roo.log('changing to ul' );
763 this.glyphicon = 'caret';
764 if (Roo.bootstrap.version == 4) {
765 this.fa = 'caret-down';
770 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
772 //gsRoo.log(this.parentType);
773 if (this.parentType === 'Navbar' && !this.parent().bar) {
774 Roo.log('changing to li?');
783 href : this.href || '#'
786 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
787 cfg.cls += ' dropdown';
794 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
796 if (this.glyphicon) {
797 cfg.html = ' ' + cfg.html;
802 cls: 'glyphicon glyphicon-' + this.glyphicon
807 cfg.html = ' ' + cfg.html;
812 cls: 'fa fas fa-' + this.fa
822 // cfg.cls='btn roo-button';
826 var value = cfg.html;
831 cls: 'glyphicon glyphicon-' + this.glyphicon,
838 cls: 'fa fas fa-' + this.fa,
843 var bw = this.badge_weight.length ? this.badge_weight :
844 (this.weight.length ? this.weight : 'secondary');
845 bw = bw == 'default' ? 'secondary' : bw;
851 cls: 'badge badge-' + bw,
860 cfg.cls += ' dropdown';
861 cfg.html = typeof(cfg.html) != 'undefined' ?
862 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
865 if (cfg.tag !== 'a' && this.href !== '') {
866 throw "Tag must be a to set href.";
867 } else if (this.href.length > 0) {
868 cfg.href = this.href;
871 if(this.removeClass){
876 cfg.target = this.target;
881 initEvents: function() {
882 // Roo.log('init events?');
883 // Roo.log(this.el.dom);
886 if (typeof (this.menu) != 'undefined') {
887 this.menu.parentType = this.xtype;
888 this.menu.triggerEl = this.el;
889 this.addxtype(Roo.apply({}, this.menu));
893 if (this.el.hasClass('roo-button')) {
894 this.el.on('click', this.onClick, this);
896 this.el.select('.roo-button').on('click', this.onClick, this);
899 if(this.removeClass){
900 this.el.on('click', this.onClick, this);
903 this.el.enableDisplayMode();
906 onClick : function(e)
912 Roo.log('button on click ');
913 if(this.preventDefault){
917 if (this.pressed === true || this.pressed === false) {
918 this.toggleActive(e);
922 this.fireEvent('click', this, e);
926 * Enables this button
930 this.disabled = false;
931 this.el.removeClass('disabled');
935 * Disable this button
939 this.disabled = true;
940 this.el.addClass('disabled');
943 * sets the active state on/off,
944 * @param {Boolean} state (optional) Force a particular state
946 setActive : function(v) {
948 this.el[v ? 'addClass' : 'removeClass']('active');
952 * toggles the current active state
954 toggleActive : function(e)
956 this.setActive(!this.pressed);
957 this.fireEvent('toggle', this, e, !this.pressed);
960 * get the current active state
961 * @return {boolean} true if it's active
963 isActive : function()
965 return this.el.hasClass('active');
968 * set the text of the first selected button
970 setText : function(str)
972 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
975 * get the text of the first selected button
979 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
982 setWeight : function(str)
984 this.el.removeClass(this.weightClass);
986 var outline = this.outline ? 'outline-' : '';
987 if (str == 'default') {
988 this.el.addClass('btn-default btn-outline-secondary');
991 this.el.addClass('btn-' + outline + str);
1005 * @class Roo.bootstrap.Column
1006 * @extends Roo.bootstrap.Component
1007 * Bootstrap Column class
1008 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1009 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1010 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1011 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1012 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1013 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1014 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1015 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1018 * @cfg {Boolean} hidden (true|false) hide the element
1019 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1020 * @cfg {String} fa (ban|check|...) font awesome icon
1021 * @cfg {Number} fasize (1|2|....) font awsome size
1023 * @cfg {String} icon (info-sign|check|...) glyphicon name
1025 * @cfg {String} html content of column.
1028 * Create a new Column
1029 * @param {Object} config The config object
1032 Roo.bootstrap.Column = function(config){
1033 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1036 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1054 getAutoCreate : function(){
1055 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1063 ['xs','sm','md','lg'].map(function(size){
1064 //Roo.log( size + ':' + settings[size]);
1066 if (settings[size+'off'] !== false) {
1067 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1070 if (settings[size] === false) {
1074 if (!settings[size]) { // 0 = hidden
1075 cfg.cls += ' hidden-' + size;
1078 cfg.cls += ' col-' + size + '-' + settings[size];
1083 cfg.cls += ' hidden';
1086 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1087 cfg.cls +=' alert alert-' + this.alert;
1091 if (this.html.length) {
1092 cfg.html = this.html;
1096 if (this.fasize > 1) {
1097 fasize = ' fa-' + this.fasize + 'x';
1099 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1104 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1123 * @class Roo.bootstrap.Container
1124 * @extends Roo.bootstrap.Component
1125 * Bootstrap Container class
1126 * @cfg {Boolean} jumbotron is it a jumbotron element
1127 * @cfg {String} html content of element
1128 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1129 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1130 * @cfg {String} header content of header (for panel)
1131 * @cfg {String} footer content of footer (for panel)
1132 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1133 * @cfg {String} tag (header|aside|section) type of HTML tag.
1134 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1135 * @cfg {String} fa font awesome icon
1136 * @cfg {String} icon (info-sign|check|...) glyphicon name
1137 * @cfg {Boolean} hidden (true|false) hide the element
1138 * @cfg {Boolean} expandable (true|false) default false
1139 * @cfg {Boolean} expanded (true|false) default true
1140 * @cfg {String} rheader contet on the right of header
1141 * @cfg {Boolean} clickable (true|false) default false
1145 * Create a new Container
1146 * @param {Object} config The config object
1149 Roo.bootstrap.Container = function(config){
1150 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1156 * After the panel has been expand
1158 * @param {Roo.bootstrap.Container} this
1163 * After the panel has been collapsed
1165 * @param {Roo.bootstrap.Container} this
1170 * When a element is chick
1171 * @param {Roo.bootstrap.Container} this
1172 * @param {Roo.EventObject} e
1178 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1196 getChildContainer : function() {
1202 if (this.panel.length) {
1203 return this.el.select('.panel-body',true).first();
1210 getAutoCreate : function(){
1213 tag : this.tag || 'div',
1217 if (this.jumbotron) {
1218 cfg.cls = 'jumbotron';
1223 // - this is applied by the parent..
1225 // cfg.cls = this.cls + '';
1228 if (this.sticky.length) {
1230 var bd = Roo.get(document.body);
1231 if (!bd.hasClass('bootstrap-sticky')) {
1232 bd.addClass('bootstrap-sticky');
1233 Roo.select('html',true).setStyle('height', '100%');
1236 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1240 if (this.well.length) {
1241 switch (this.well) {
1244 cfg.cls +=' well well-' +this.well;
1253 cfg.cls += ' hidden';
1257 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1258 cfg.cls +=' alert alert-' + this.alert;
1263 if (this.panel.length) {
1264 cfg.cls += ' panel panel-' + this.panel;
1266 if (this.header.length) {
1270 if(this.expandable){
1272 cfg.cls = cfg.cls + ' expandable';
1276 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1284 cls : 'panel-title',
1285 html : (this.expandable ? ' ' : '') + this.header
1289 cls: 'panel-header-right',
1295 cls : 'panel-heading',
1296 style : this.expandable ? 'cursor: pointer' : '',
1304 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1309 if (this.footer.length) {
1311 cls : 'panel-footer',
1320 body.html = this.html || cfg.html;
1321 // prefix with the icons..
1323 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1326 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1331 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1332 cfg.cls = 'container';
1338 initEvents: function()
1340 if(this.expandable){
1341 var headerEl = this.headerEl();
1344 headerEl.on('click', this.onToggleClick, this);
1349 this.el.on('click', this.onClick, this);
1354 onToggleClick : function()
1356 var headerEl = this.headerEl();
1372 if(this.fireEvent('expand', this)) {
1374 this.expanded = true;
1376 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1378 this.el.select('.panel-body',true).first().removeClass('hide');
1380 var toggleEl = this.toggleEl();
1386 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1391 collapse : function()
1393 if(this.fireEvent('collapse', this)) {
1395 this.expanded = false;
1397 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1398 this.el.select('.panel-body',true).first().addClass('hide');
1400 var toggleEl = this.toggleEl();
1406 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1410 toggleEl : function()
1412 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1416 return this.el.select('.panel-heading .fa',true).first();
1419 headerEl : function()
1421 if(!this.el || !this.panel.length || !this.header.length){
1425 return this.el.select('.panel-heading',true).first()
1430 if(!this.el || !this.panel.length){
1434 return this.el.select('.panel-body',true).first()
1437 titleEl : function()
1439 if(!this.el || !this.panel.length || !this.header.length){
1443 return this.el.select('.panel-title',true).first();
1446 setTitle : function(v)
1448 var titleEl = this.titleEl();
1454 titleEl.dom.innerHTML = v;
1457 getTitle : function()
1460 var titleEl = this.titleEl();
1466 return titleEl.dom.innerHTML;
1469 setRightTitle : function(v)
1471 var t = this.el.select('.panel-header-right',true).first();
1477 t.dom.innerHTML = v;
1480 onClick : function(e)
1484 this.fireEvent('click', this, e);
1497 * @class Roo.bootstrap.Img
1498 * @extends Roo.bootstrap.Component
1499 * Bootstrap Img class
1500 * @cfg {Boolean} imgResponsive false | true
1501 * @cfg {String} border rounded | circle | thumbnail
1502 * @cfg {String} src image source
1503 * @cfg {String} alt image alternative text
1504 * @cfg {String} href a tag href
1505 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1506 * @cfg {String} xsUrl xs image source
1507 * @cfg {String} smUrl sm image source
1508 * @cfg {String} mdUrl md image source
1509 * @cfg {String} lgUrl lg image source
1512 * Create a new Input
1513 * @param {Object} config The config object
1516 Roo.bootstrap.Img = function(config){
1517 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1523 * The img click event for the img.
1524 * @param {Roo.EventObject} e
1530 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1532 imgResponsive: true,
1542 getAutoCreate : function()
1544 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1545 return this.createSingleImg();
1550 cls: 'roo-image-responsive-group',
1555 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1557 if(!_this[size + 'Url']){
1563 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1564 html: _this.html || cfg.html,
1565 src: _this[size + 'Url']
1568 img.cls += ' roo-image-responsive-' + size;
1570 var s = ['xs', 'sm', 'md', 'lg'];
1572 s.splice(s.indexOf(size), 1);
1574 Roo.each(s, function(ss){
1575 img.cls += ' hidden-' + ss;
1578 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1579 cfg.cls += ' img-' + _this.border;
1583 cfg.alt = _this.alt;
1596 a.target = _this.target;
1600 cfg.cn.push((_this.href) ? a : img);
1607 createSingleImg : function()
1611 cls: (this.imgResponsive) ? 'img-responsive' : '',
1613 src : 'about:blank' // just incase src get's set to undefined?!?
1616 cfg.html = this.html || cfg.html;
1618 cfg.src = this.src || cfg.src;
1620 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1621 cfg.cls += ' img-' + this.border;
1638 a.target = this.target;
1643 return (this.href) ? a : cfg;
1646 initEvents: function()
1649 this.el.on('click', this.onClick, this);
1654 onClick : function(e)
1656 Roo.log('img onclick');
1657 this.fireEvent('click', this, e);
1660 * Sets the url of the image - used to update it
1661 * @param {String} url the url of the image
1664 setSrc : function(url)
1668 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1669 this.el.dom.src = url;
1673 this.el.select('img', true).first().dom.src = url;
1689 * @class Roo.bootstrap.Link
1690 * @extends Roo.bootstrap.Component
1691 * Bootstrap Link Class
1692 * @cfg {String} alt image alternative text
1693 * @cfg {String} href a tag href
1694 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1695 * @cfg {String} html the content of the link.
1696 * @cfg {String} anchor name for the anchor link
1697 * @cfg {String} fa - favicon
1699 * @cfg {Boolean} preventDefault (true | false) default false
1703 * Create a new Input
1704 * @param {Object} config The config object
1707 Roo.bootstrap.Link = function(config){
1708 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1714 * The img click event for the img.
1715 * @param {Roo.EventObject} e
1721 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1725 preventDefault: false,
1731 getAutoCreate : function()
1733 var html = this.html || '';
1735 if (this.fa !== false) {
1736 html = '<i class="fa fa-' + this.fa + '"></i>';
1741 // anchor's do not require html/href...
1742 if (this.anchor === false) {
1744 cfg.href = this.href || '#';
1746 cfg.name = this.anchor;
1747 if (this.html !== false || this.fa !== false) {
1750 if (this.href !== false) {
1751 cfg.href = this.href;
1755 if(this.alt !== false){
1760 if(this.target !== false) {
1761 cfg.target = this.target;
1767 initEvents: function() {
1769 if(!this.href || this.preventDefault){
1770 this.el.on('click', this.onClick, this);
1774 onClick : function(e)
1776 if(this.preventDefault){
1779 //Roo.log('img onclick');
1780 this.fireEvent('click', this, e);
1793 * @class Roo.bootstrap.Header
1794 * @extends Roo.bootstrap.Component
1795 * Bootstrap Header class
1796 * @cfg {String} html content of header
1797 * @cfg {Number} level (1|2|3|4|5|6) default 1
1800 * Create a new Header
1801 * @param {Object} config The config object
1805 Roo.bootstrap.Header = function(config){
1806 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1809 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1817 getAutoCreate : function(){
1822 tag: 'h' + (1 *this.level),
1823 html: this.html || ''
1835 * Ext JS Library 1.1.1
1836 * Copyright(c) 2006-2007, Ext JS, LLC.
1838 * Originally Released Under LGPL - original licence link has changed is not relivant.
1841 * <script type="text/javascript">
1845 * @class Roo.bootstrap.MenuMgr
1846 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1849 Roo.bootstrap.MenuMgr = function(){
1850 var menus, active, groups = {}, attached = false, lastShow = new Date();
1852 // private - called when first menu is created
1855 active = new Roo.util.MixedCollection();
1856 Roo.get(document).addKeyListener(27, function(){
1857 if(active.length > 0){
1865 if(active && active.length > 0){
1866 var c = active.clone();
1876 if(active.length < 1){
1877 Roo.get(document).un("mouseup", onMouseDown);
1885 var last = active.last();
1886 lastShow = new Date();
1889 Roo.get(document).on("mouseup", onMouseDown);
1894 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1895 m.parentMenu.activeChild = m;
1896 }else if(last && last.isVisible()){
1897 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1902 function onBeforeHide(m){
1904 m.activeChild.hide();
1906 if(m.autoHideTimer){
1907 clearTimeout(m.autoHideTimer);
1908 delete m.autoHideTimer;
1913 function onBeforeShow(m){
1914 var pm = m.parentMenu;
1915 if(!pm && !m.allowOtherMenus){
1917 }else if(pm && pm.activeChild && active != m){
1918 pm.activeChild.hide();
1922 // private this should really trigger on mouseup..
1923 function onMouseDown(e){
1924 Roo.log("on Mouse Up");
1926 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1927 Roo.log("MenuManager hideAll");
1936 function onBeforeCheck(mi, state){
1938 var g = groups[mi.group];
1939 for(var i = 0, l = g.length; i < l; i++){
1941 g[i].setChecked(false);
1950 * Hides all menus that are currently visible
1952 hideAll : function(){
1957 register : function(menu){
1961 menus[menu.id] = menu;
1962 menu.on("beforehide", onBeforeHide);
1963 menu.on("hide", onHide);
1964 menu.on("beforeshow", onBeforeShow);
1965 menu.on("show", onShow);
1967 if(g && menu.events["checkchange"]){
1971 groups[g].push(menu);
1972 menu.on("checkchange", onCheck);
1977 * Returns a {@link Roo.menu.Menu} object
1978 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1979 * be used to generate and return a new Menu instance.
1981 get : function(menu){
1982 if(typeof menu == "string"){ // menu id
1984 }else if(menu.events){ // menu instance
1987 /*else if(typeof menu.length == 'number'){ // array of menu items?
1988 return new Roo.bootstrap.Menu({items:menu});
1989 }else{ // otherwise, must be a config
1990 return new Roo.bootstrap.Menu(menu);
1997 unregister : function(menu){
1998 delete menus[menu.id];
1999 menu.un("beforehide", onBeforeHide);
2000 menu.un("hide", onHide);
2001 menu.un("beforeshow", onBeforeShow);
2002 menu.un("show", onShow);
2004 if(g && menu.events["checkchange"]){
2005 groups[g].remove(menu);
2006 menu.un("checkchange", onCheck);
2011 registerCheckable : function(menuItem){
2012 var g = menuItem.group;
2017 groups[g].push(menuItem);
2018 menuItem.on("beforecheckchange", onBeforeCheck);
2023 unregisterCheckable : function(menuItem){
2024 var g = menuItem.group;
2026 groups[g].remove(menuItem);
2027 menuItem.un("beforecheckchange", onBeforeCheck);
2039 * @class Roo.bootstrap.Menu
2040 * @extends Roo.bootstrap.Component
2041 * Bootstrap Menu class - container for MenuItems
2042 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2043 * @cfg {bool} hidden if the menu should be hidden when rendered.
2044 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2045 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2049 * @param {Object} config The config object
2053 Roo.bootstrap.Menu = function(config){
2054 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2055 if (this.registerMenu && this.type != 'treeview') {
2056 Roo.bootstrap.MenuMgr.register(this);
2063 * Fires before this menu is displayed
2064 * @param {Roo.menu.Menu} this
2069 * Fires before this menu is hidden
2070 * @param {Roo.menu.Menu} this
2075 * Fires after this menu is displayed
2076 * @param {Roo.menu.Menu} this
2081 * Fires after this menu is hidden
2082 * @param {Roo.menu.Menu} this
2087 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2088 * @param {Roo.menu.Menu} this
2089 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2090 * @param {Roo.EventObject} e
2095 * Fires when the mouse is hovering over this menu
2096 * @param {Roo.menu.Menu} this
2097 * @param {Roo.EventObject} e
2098 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2103 * Fires when the mouse exits this menu
2104 * @param {Roo.menu.Menu} this
2105 * @param {Roo.EventObject} e
2106 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2111 * Fires when a menu item contained in this menu is clicked
2112 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2113 * @param {Roo.EventObject} e
2117 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2120 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2124 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2127 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2129 registerMenu : true,
2131 menuItems :false, // stores the menu items..
2141 getChildContainer : function() {
2145 getAutoCreate : function(){
2147 //if (['right'].indexOf(this.align)!==-1) {
2148 // cfg.cn[1].cls += ' pull-right'
2154 cls : 'dropdown-menu' ,
2155 style : 'z-index:1000'
2159 if (this.type === 'submenu') {
2160 cfg.cls = 'submenu active';
2162 if (this.type === 'treeview') {
2163 cfg.cls = 'treeview-menu';
2168 initEvents : function() {
2170 // Roo.log("ADD event");
2171 // Roo.log(this.triggerEl.dom);
2173 this.triggerEl.on('click', this.onTriggerClick, this);
2175 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2178 if (this.triggerEl.hasClass('nav-item')) {
2179 // dropdown toggle on the 'a' in BS4?
2180 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2182 this.triggerEl.addClass('dropdown-toggle');
2185 this.el.on('touchstart' , this.onTouch, this);
2187 this.el.on('click' , this.onClick, this);
2189 this.el.on("mouseover", this.onMouseOver, this);
2190 this.el.on("mouseout", this.onMouseOut, this);
2194 findTargetItem : function(e)
2196 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2200 //Roo.log(t); Roo.log(t.id);
2202 //Roo.log(this.menuitems);
2203 return this.menuitems.get(t.id);
2205 //return this.items.get(t.menuItemId);
2211 onTouch : function(e)
2213 Roo.log("menu.onTouch");
2214 //e.stopEvent(); this make the user popdown broken
2218 onClick : function(e)
2220 Roo.log("menu.onClick");
2222 var t = this.findTargetItem(e);
2223 if(!t || t.isContainer){
2228 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2229 if(t == this.activeItem && t.shouldDeactivate(e)){
2230 this.activeItem.deactivate();
2231 delete this.activeItem;
2235 this.setActiveItem(t, true);
2243 Roo.log('pass click event');
2247 this.fireEvent("click", this, t, e);
2251 if(!t.href.length || t.href == '#'){
2252 (function() { _this.hide(); }).defer(100);
2257 onMouseOver : function(e){
2258 var t = this.findTargetItem(e);
2261 // if(t.canActivate && !t.disabled){
2262 // this.setActiveItem(t, true);
2266 this.fireEvent("mouseover", this, e, t);
2268 isVisible : function(){
2269 return !this.hidden;
2271 onMouseOut : function(e){
2272 var t = this.findTargetItem(e);
2275 // if(t == this.activeItem && t.shouldDeactivate(e)){
2276 // this.activeItem.deactivate();
2277 // delete this.activeItem;
2280 this.fireEvent("mouseout", this, e, t);
2285 * Displays this menu relative to another element
2286 * @param {String/HTMLElement/Roo.Element} element The element to align to
2287 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2288 * the element (defaults to this.defaultAlign)
2289 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2291 show : function(el, pos, parentMenu){
2292 this.parentMenu = parentMenu;
2296 this.fireEvent("beforeshow", this);
2297 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2300 * Displays this menu at a specific xy position
2301 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2302 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2304 showAt : function(xy, parentMenu, /* private: */_e){
2305 this.parentMenu = parentMenu;
2310 this.fireEvent("beforeshow", this);
2311 //xy = this.el.adjustForConstraints(xy);
2315 this.hideMenuItems();
2316 this.hidden = false;
2317 this.triggerEl.addClass('open');
2318 this.el.addClass('show');
2320 // reassign x when hitting right
2321 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2322 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2325 // reassign y when hitting bottom
2326 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2327 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2330 // but the list may align on trigger left or trigger top... should it be a properity?
2332 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2337 this.fireEvent("show", this);
2343 this.doFocus.defer(50, this);
2347 doFocus : function(){
2349 this.focusEl.focus();
2354 * Hides this menu and optionally all parent menus
2355 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2357 hide : function(deep)
2360 this.hideMenuItems();
2361 if(this.el && this.isVisible()){
2362 this.fireEvent("beforehide", this);
2363 if(this.activeItem){
2364 this.activeItem.deactivate();
2365 this.activeItem = null;
2367 this.triggerEl.removeClass('open');;
2368 this.el.removeClass('show');
2370 this.fireEvent("hide", this);
2372 if(deep === true && this.parentMenu){
2373 this.parentMenu.hide(true);
2377 onTriggerClick : function(e)
2379 Roo.log('trigger click');
2381 var target = e.getTarget();
2383 Roo.log(target.nodeName.toLowerCase());
2385 if(target.nodeName.toLowerCase() === 'i'){
2391 onTriggerPress : function(e)
2393 Roo.log('trigger press');
2394 //Roo.log(e.getTarget());
2395 // Roo.log(this.triggerEl.dom);
2397 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2398 var pel = Roo.get(e.getTarget());
2399 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2400 Roo.log('is treeview or dropdown?');
2404 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2408 if (this.isVisible()) {
2413 this.show(this.triggerEl, '?', false);
2416 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2423 hideMenuItems : function()
2425 Roo.log("hide Menu Items");
2429 //$(backdrop).remove()
2430 this.el.select('.open',true).each(function(aa) {
2432 aa.removeClass('open');
2433 //var parent = getParent($(this))
2434 //var relatedTarget = { relatedTarget: this }
2436 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2437 //if (e.isDefaultPrevented()) return
2438 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2441 addxtypeChild : function (tree, cntr) {
2442 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2444 this.menuitems.add(comp);
2456 this.getEl().dom.innerHTML = '';
2457 this.menuitems.clear();
2471 * @class Roo.bootstrap.MenuItem
2472 * @extends Roo.bootstrap.Component
2473 * Bootstrap MenuItem class
2474 * @cfg {String} html the menu label
2475 * @cfg {String} href the link
2476 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2477 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2478 * @cfg {Boolean} active used on sidebars to highlight active itesm
2479 * @cfg {String} fa favicon to show on left of menu item.
2480 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2484 * Create a new MenuItem
2485 * @param {Object} config The config object
2489 Roo.bootstrap.MenuItem = function(config){
2490 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2495 * The raw click event for the entire grid.
2496 * @param {Roo.bootstrap.MenuItem} this
2497 * @param {Roo.EventObject} e
2503 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2507 preventDefault: false,
2508 isContainer : false,
2512 getAutoCreate : function(){
2514 if(this.isContainer){
2517 cls: 'dropdown-menu-item '
2527 cls : 'dropdown-item',
2532 if (this.fa !== false) {
2535 cls : 'fa fa-' + this.fa
2544 cls: 'dropdown-menu-item',
2547 if (this.parent().type == 'treeview') {
2548 cfg.cls = 'treeview-menu';
2551 cfg.cls += ' active';
2556 anc.href = this.href || cfg.cn[0].href ;
2557 ctag.html = this.html || cfg.cn[0].html ;
2561 initEvents: function()
2563 if (this.parent().type == 'treeview') {
2564 this.el.select('a').on('click', this.onClick, this);
2568 this.menu.parentType = this.xtype;
2569 this.menu.triggerEl = this.el;
2570 this.menu = this.addxtype(Roo.apply({}, this.menu));
2574 onClick : function(e)
2576 Roo.log('item on click ');
2578 if(this.preventDefault){
2581 //this.parent().hideMenuItems();
2583 this.fireEvent('click', this, e);
2602 * @class Roo.bootstrap.MenuSeparator
2603 * @extends Roo.bootstrap.Component
2604 * Bootstrap MenuSeparator class
2607 * Create a new MenuItem
2608 * @param {Object} config The config object
2612 Roo.bootstrap.MenuSeparator = function(config){
2613 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2616 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2618 getAutoCreate : function(){
2637 * @class Roo.bootstrap.Modal
2638 * @extends Roo.bootstrap.Component
2639 * Bootstrap Modal class
2640 * @cfg {String} title Title of dialog
2641 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2642 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2643 * @cfg {Boolean} specificTitle default false
2644 * @cfg {Array} buttons Array of buttons or standard button set..
2645 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2646 * @cfg {Boolean} animate default true
2647 * @cfg {Boolean} allow_close default true
2648 * @cfg {Boolean} fitwindow default false
2649 * @cfg {String} size (sm|lg) default empty
2650 * @cfg {Number} max_width set the max width of modal
2654 * Create a new Modal Dialog
2655 * @param {Object} config The config object
2658 Roo.bootstrap.Modal = function(config){
2659 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2664 * The raw btnclick event for the button
2665 * @param {Roo.EventObject} e
2670 * Fire when dialog resize
2671 * @param {Roo.bootstrap.Modal} this
2672 * @param {Roo.EventObject} e
2676 this.buttons = this.buttons || [];
2679 this.tmpl = Roo.factory(this.tmpl);
2684 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2686 title : 'test dialog',
2696 specificTitle: false,
2698 buttonPosition: 'right',
2721 onRender : function(ct, position)
2723 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2726 var cfg = Roo.apply({}, this.getAutoCreate());
2729 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2731 //if (!cfg.name.length) {
2735 cfg.cls += ' ' + this.cls;
2738 cfg.style = this.style;
2740 this.el = Roo.get(document.body).createChild(cfg, position);
2742 //var type = this.el.dom.type;
2745 if(this.tabIndex !== undefined){
2746 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2749 this.dialogEl = this.el.select('.modal-dialog',true).first();
2750 this.bodyEl = this.el.select('.modal-body',true).first();
2751 this.closeEl = this.el.select('.modal-header .close', true).first();
2752 this.headerEl = this.el.select('.modal-header',true).first();
2753 this.titleEl = this.el.select('.modal-title',true).first();
2754 this.footerEl = this.el.select('.modal-footer',true).first();
2756 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2758 //this.el.addClass("x-dlg-modal");
2760 if (this.buttons.length) {
2761 Roo.each(this.buttons, function(bb) {
2762 var b = Roo.apply({}, bb);
2763 b.xns = b.xns || Roo.bootstrap;
2764 b.xtype = b.xtype || 'Button';
2765 if (typeof(b.listeners) == 'undefined') {
2766 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2769 var btn = Roo.factory(b);
2771 btn.render(this.getButtonContainer());
2775 // render the children.
2778 if(typeof(this.items) != 'undefined'){
2779 var items = this.items;
2782 for(var i =0;i < items.length;i++) {
2783 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2787 this.items = nitems;
2789 // where are these used - they used to be body/close/footer
2793 //this.el.addClass([this.fieldClass, this.cls]);
2797 getAutoCreate : function()
2801 html : this.html || ''
2806 cls : 'modal-title',
2810 if(this.specificTitle){
2816 if (this.allow_close && Roo.bootstrap.version == 3) {
2826 if (this.allow_close && Roo.bootstrap.version == 4) {
2836 if(this.size.length){
2837 size = 'modal-' + this.size;
2840 var footer = Roo.bootstrap.version == 3 ?
2842 cls : 'modal-footer',
2846 cls: 'btn-' + this.buttonPosition
2851 { // BS4 uses mr-auto on left buttons....
2852 cls : 'modal-footer'
2863 cls: "modal-dialog " + size,
2866 cls : "modal-content",
2869 cls : 'modal-header',
2884 modal.cls += ' fade';
2890 getChildContainer : function() {
2895 getButtonContainer : function() {
2897 return Roo.bootstrap.version == 4 ?
2898 this.el.select('.modal-footer',true).first()
2899 : this.el.select('.modal-footer div',true).first();
2902 initEvents : function()
2904 if (this.allow_close) {
2905 this.closeEl.on('click', this.hide, this);
2907 Roo.EventManager.onWindowResize(this.resize, this, true);
2914 this.maskEl.setSize(
2915 Roo.lib.Dom.getViewWidth(true),
2916 Roo.lib.Dom.getViewHeight(true)
2919 if (this.fitwindow) {
2921 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2922 this.height || Roo.lib.Dom.getViewportHeight(true) - 60
2927 if(this.max_width !== 0) {
2929 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2932 this.setSize(w, this.height);
2936 if(this.max_height) {
2937 this.setSize(w,Math.min(
2939 Roo.lib.Dom.getViewportHeight(true) - 60
2945 if(!this.fit_content) {
2946 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2950 this.setSize(w, Math.min(
2952 this.headerEl.getHeight() +
2953 this.footerEl.getHeight() +
2954 this.getChildHeight(this.bodyEl.dom.childNodes),
2955 Roo.lib.Dom.getViewportHeight(true) - 60)
2961 setSize : function(w,h)
2972 if (!this.rendered) {
2976 //this.el.setStyle('display', 'block');
2977 this.el.removeClass('hideing');
2978 this.el.dom.style.display='block';
2980 Roo.get(document.body).addClass('modal-open');
2982 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2985 this.el.addClass('show');
2986 this.el.addClass('in');
2989 this.el.addClass('show');
2990 this.el.addClass('in');
2993 // not sure how we can show data in here..
2995 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2998 Roo.get(document.body).addClass("x-body-masked");
3000 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3001 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3002 this.maskEl.dom.style.display = 'block';
3003 this.maskEl.addClass('show');
3008 this.fireEvent('show', this);
3010 // set zindex here - otherwise it appears to be ignored...
3011 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3014 this.items.forEach( function(e) {
3015 e.layout ? e.layout() : false;
3023 if(this.fireEvent("beforehide", this) !== false){
3025 this.maskEl.removeClass('show');
3027 this.maskEl.dom.style.display = '';
3028 Roo.get(document.body).removeClass("x-body-masked");
3029 this.el.removeClass('in');
3030 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3032 if(this.animate){ // why
3033 this.el.addClass('hideing');
3034 this.el.removeClass('show');
3036 if (!this.el.hasClass('hideing')) {
3037 return; // it's been shown again...
3040 this.el.dom.style.display='';
3042 Roo.get(document.body).removeClass('modal-open');
3043 this.el.removeClass('hideing');
3047 this.el.removeClass('show');
3048 this.el.dom.style.display='';
3049 Roo.get(document.body).removeClass('modal-open');
3052 this.fireEvent('hide', this);
3055 isVisible : function()
3058 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3062 addButton : function(str, cb)
3066 var b = Roo.apply({}, { html : str } );
3067 b.xns = b.xns || Roo.bootstrap;
3068 b.xtype = b.xtype || 'Button';
3069 if (typeof(b.listeners) == 'undefined') {
3070 b.listeners = { click : cb.createDelegate(this) };
3073 var btn = Roo.factory(b);
3075 btn.render(this.getButtonContainer());
3081 setDefaultButton : function(btn)
3083 //this.el.select('.modal-footer').()
3087 resizeTo: function(w,h)
3091 this.dialogEl.setWidth(w);
3092 if (this.diff === false) {
3093 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
3096 this.bodyEl.setHeight(h - this.diff);
3098 this.fireEvent('resize', this);
3101 setContentSize : function(w, h)
3105 onButtonClick: function(btn,e)
3108 this.fireEvent('btnclick', btn.name, e);
3111 * Set the title of the Dialog
3112 * @param {String} str new Title
3114 setTitle: function(str) {
3115 this.titleEl.dom.innerHTML = str;
3118 * Set the body of the Dialog
3119 * @param {String} str new Title
3121 setBody: function(str) {
3122 this.bodyEl.dom.innerHTML = str;
3125 * Set the body of the Dialog using the template
3126 * @param {Obj} data - apply this data to the template and replace the body contents.
3128 applyBody: function(obj)
3131 Roo.log("Error - using apply Body without a template");
3134 this.tmpl.overwrite(this.bodyEl, obj);
3137 getChildHeight : function(child_nodes)
3141 child_nodes.length == 0
3146 var child_height = 0;
3148 for(var i = 0; i < child_nodes.length; i++) {
3151 * for modal with tabs...
3152 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3154 var layout_childs = child_nodes[i].childNodes;
3156 for(var j = 0; j < layout_childs.length; j++) {
3158 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3160 var layout_body_childs = layout_childs[j].childNodes;
3162 for(var k = 0; k < layout_body_childs.length; k++) {
3164 if(layout_body_childs[k].classList.contains('navbar')) {
3165 child_height += layout_body_childs[k].offsetHeight;
3169 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3171 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3173 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3175 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3176 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3191 child_height += child_nodes[i].offsetHeight;
3192 // Roo.log(child_nodes[i].offsetHeight);
3195 return child_height;
3201 Roo.apply(Roo.bootstrap.Modal, {
3203 * Button config that displays a single OK button
3212 * Button config that displays Yes and No buttons
3228 * Button config that displays OK and Cancel buttons
3243 * Button config that displays Yes, No and Cancel buttons
3267 * messagebox - can be used as a replace
3271 * @class Roo.MessageBox
3272 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3276 Roo.Msg.alert('Status', 'Changes saved successfully.');
3278 // Prompt for user data:
3279 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3281 // process text value...
3285 // Show a dialog using config options:
3287 title:'Save Changes?',
3288 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3289 buttons: Roo.Msg.YESNOCANCEL,
3296 Roo.bootstrap.MessageBox = function(){
3297 var dlg, opt, mask, waitTimer;
3298 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3299 var buttons, activeTextEl, bwidth;
3303 var handleButton = function(button){
3305 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3309 var handleHide = function(){
3311 dlg.el.removeClass(opt.cls);
3314 // Roo.TaskMgr.stop(waitTimer);
3315 // waitTimer = null;
3320 var updateButtons = function(b){
3323 buttons["ok"].hide();
3324 buttons["cancel"].hide();
3325 buttons["yes"].hide();
3326 buttons["no"].hide();
3327 //dlg.footer.dom.style.display = 'none';
3330 dlg.footerEl.dom.style.display = '';
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);
3607 this.updateProgress(0);
3608 activeTextEl.dom.value = opt.value || "";
3610 dlg.setDefaultButton(activeTextEl);
3612 var bs = opt.buttons;
3616 }else if(bs && bs.yes){
3617 db = buttons["yes"];
3619 dlg.setDefaultButton(db);
3621 bwidth = updateButtons(opt.buttons);
3622 this.updateText(opt.msg);
3624 d.el.addClass(opt.cls);
3626 d.proxyDrag = opt.proxyDrag === true;
3627 d.modal = opt.modal !== false;
3628 d.mask = opt.modal !== false ? mask : false;
3630 // force it to the end of the z-index stack so it gets a cursor in FF
3631 document.body.appendChild(dlg.el.dom);
3632 d.animateTarget = null;
3633 d.show(options.animEl);
3639 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3640 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3641 * and closing the message box when the process is complete.
3642 * @param {String} title The title bar text
3643 * @param {String} msg The message box body text
3644 * @return {Roo.MessageBox} This message box
3646 progress : function(title, msg){
3653 minWidth: this.minProgressWidth,
3660 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3661 * If a callback function is passed it will be called after the user clicks the button, and the
3662 * id of the button that was clicked will be passed as the only parameter to the callback
3663 * (could also be the top-right close button).
3664 * @param {String} title The title bar text
3665 * @param {String} msg The message box body text
3666 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3667 * @param {Object} scope (optional) The scope of the callback function
3668 * @return {Roo.MessageBox} This message box
3670 alert : function(title, msg, fn, scope)
3685 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3686 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3687 * You are responsible for closing the message box when the process is complete.
3688 * @param {String} msg The message box body text
3689 * @param {String} title (optional) The title bar text
3690 * @return {Roo.MessageBox} This message box
3692 wait : function(msg, title){
3703 waitTimer = Roo.TaskMgr.start({
3705 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3713 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3714 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3715 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3716 * @param {String} title The title bar text
3717 * @param {String} msg The message box body text
3718 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3719 * @param {Object} scope (optional) The scope of the callback function
3720 * @return {Roo.MessageBox} This message box
3722 confirm : function(title, msg, fn, scope){
3726 buttons: this.YESNO,
3735 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3736 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3737 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3738 * (could also be the top-right close button) and the text that was entered will be passed as the two
3739 * parameters to the callback.
3740 * @param {String} title The title bar text
3741 * @param {String} msg The message box body text
3742 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3743 * @param {Object} scope (optional) The scope of the callback function
3744 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3745 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3746 * @return {Roo.MessageBox} This message box
3748 prompt : function(title, msg, fn, scope, multiline){
3752 buttons: this.OKCANCEL,
3757 multiline: multiline,
3764 * Button config that displays a single OK button
3769 * Button config that displays Yes and No buttons
3772 YESNO : {yes:true, no:true},
3774 * Button config that displays OK and Cancel buttons
3777 OKCANCEL : {ok:true, cancel:true},
3779 * Button config that displays Yes, No and Cancel buttons
3782 YESNOCANCEL : {yes:true, no:true, cancel:true},
3785 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3788 defaultTextHeight : 75,
3790 * The maximum width in pixels of the message box (defaults to 600)
3795 * The minimum width in pixels of the message box (defaults to 100)
3800 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3801 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3804 minProgressWidth : 250,
3806 * An object containing the default button text strings that can be overriden for localized language support.
3807 * Supported properties are: ok, cancel, yes and no.
3808 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3821 * Shorthand for {@link Roo.MessageBox}
3823 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3824 Roo.Msg = Roo.Msg || Roo.MessageBox;
3833 * @class Roo.bootstrap.Navbar
3834 * @extends Roo.bootstrap.Component
3835 * Bootstrap Navbar class
3838 * Create a new Navbar
3839 * @param {Object} config The config object
3843 Roo.bootstrap.Navbar = function(config){
3844 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3848 * @event beforetoggle
3849 * Fire before toggle the menu
3850 * @param {Roo.EventObject} e
3852 "beforetoggle" : true
3856 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3865 getAutoCreate : function(){
3868 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3872 initEvents :function ()
3874 //Roo.log(this.el.select('.navbar-toggle',true));
3875 this.el.select('.navbar-toggle',true).on('click', function() {
3876 if(this.fireEvent('beforetoggle', this) !== false){
3877 var ce = this.el.select('.navbar-collapse',true).first();
3878 ce.toggleClass('in'); // old...
3879 if (ce.hasClass('collapse')) {
3881 ce.removeClass('collapse');
3882 ce.addClass('show');
3883 var h = ce.getHeight();
3885 ce.removeClass('show');
3886 // at this point we should be able to see it..
3887 ce.addClass('collapsing');
3889 ce.setHeight(0); // resize it ...
3890 ce.on('transitionend', function() {
3891 Roo.log('done transition');
3892 ce.removeClass('collapsing');
3893 ce.addClass('show');
3894 ce.removeClass('collapse');
3896 ce.dom.style.height = '';
3897 }, this, { single: true} );
3901 ce.setHeight(ce.getHeight());
3902 ce.removeClass('show');
3903 ce.addClass('collapsing');
3905 ce.on('transitionend', function() {
3906 ce.dom.style.height = '';
3907 ce.removeClass('collapsing');
3908 ce.addClass('collapse');
3909 }, this, { single: true} );
3921 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3923 var size = this.el.getSize();
3924 this.maskEl.setSize(size.width, size.height);
3925 this.maskEl.enableDisplayMode("block");
3934 getChildContainer : function()
3936 if (this.el.select('.collapse').getCount()) {
3937 return this.el.select('.collapse',true).first();
3970 * @class Roo.bootstrap.NavSimplebar
3971 * @extends Roo.bootstrap.Navbar
3972 * Bootstrap Sidebar class
3974 * @cfg {Boolean} inverse is inverted color
3976 * @cfg {String} type (nav | pills | tabs)
3977 * @cfg {Boolean} arrangement stacked | justified
3978 * @cfg {String} align (left | right) alignment
3980 * @cfg {Boolean} main (true|false) main nav bar? default false
3981 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3983 * @cfg {String} tag (header|footer|nav|div) default is nav
3985 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
3989 * Create a new Sidebar
3990 * @param {Object} config The config object
3994 Roo.bootstrap.NavSimplebar = function(config){
3995 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3998 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4014 getAutoCreate : function(){
4018 tag : this.tag || 'div',
4019 cls : 'navbar navbar-expand-lg'
4021 if (['light','white'].indexOf(this.weight) > -1) {
4022 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4024 cfg.cls += ' bg-' + this.weight;
4027 cfg.cls += ' navbar-inverse';
4031 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4033 if (Roo.bootstrap.version == 4) {
4045 this.type = this.type || 'nav';
4046 if (['tabs','pills'].indexOf(this.type)!==-1) {
4047 cfg.cn[0].cls += ' nav-' + this.type
4051 if (this.type!=='nav') {
4052 Roo.log('nav type must be nav/tabs/pills')
4054 cfg.cn[0].cls += ' navbar-nav'
4060 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
4061 cfg.cn[0].cls += ' nav-' + this.arrangement;
4065 if (this.align === 'right') {
4066 cfg.cn[0].cls += ' navbar-right';
4091 * navbar-expand-md fixed-top
4095 * @class Roo.bootstrap.NavHeaderbar
4096 * @extends Roo.bootstrap.NavSimplebar
4097 * Bootstrap Sidebar class
4099 * @cfg {String} brand what is brand
4100 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4101 * @cfg {String} brand_href href of the brand
4102 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4103 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4104 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4105 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4108 * Create a new Sidebar
4109 * @param {Object} config The config object
4113 Roo.bootstrap.NavHeaderbar = function(config){
4114 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4118 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4125 desktopCenter : false,
4128 getAutoCreate : function(){
4131 tag: this.nav || 'nav',
4132 cls: 'navbar navbar-expand-md',
4138 if (this.desktopCenter) {
4139 cn.push({cls : 'container', cn : []});
4147 cls: 'navbar-toggle navbar-toggler',
4148 'data-toggle': 'collapse',
4153 html: 'Toggle navigation'
4157 cls: 'icon-bar navbar-toggler-icon'
4170 cn.push( Roo.bootstrap.version == 4 ? btn : {
4172 cls: 'navbar-header',
4181 cls: 'collapse navbar-collapse',
4185 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4187 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4188 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4190 // tag can override this..
4192 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4195 if (this.brand !== '') {
4196 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4197 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4199 href: this.brand_href ? this.brand_href : '#',
4200 cls: 'navbar-brand',
4208 cfg.cls += ' main-nav';
4216 getHeaderChildContainer : function()
4218 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4219 return this.el.select('.navbar-header',true).first();
4222 return this.getChildContainer();
4226 initEvents : function()
4228 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4230 if (this.autohide) {
4235 Roo.get(document).on('scroll',function(e) {
4236 var ns = Roo.get(document).getScroll().top;
4237 var os = prevScroll;
4241 ft.removeClass('slideDown');
4242 ft.addClass('slideUp');
4245 ft.removeClass('slideUp');
4246 ft.addClass('slideDown');
4267 * @class Roo.bootstrap.NavSidebar
4268 * @extends Roo.bootstrap.Navbar
4269 * Bootstrap Sidebar class
4272 * Create a new Sidebar
4273 * @param {Object} config The config object
4277 Roo.bootstrap.NavSidebar = function(config){
4278 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4281 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4283 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4285 getAutoCreate : function(){
4290 cls: 'sidebar sidebar-nav'
4312 * @class Roo.bootstrap.NavGroup
4313 * @extends Roo.bootstrap.Component
4314 * Bootstrap NavGroup class
4315 * @cfg {String} align (left|right)
4316 * @cfg {Boolean} inverse
4317 * @cfg {String} type (nav|pills|tab) default nav
4318 * @cfg {String} navId - reference Id for navbar.
4322 * Create a new nav group
4323 * @param {Object} config The config object
4326 Roo.bootstrap.NavGroup = function(config){
4327 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4330 Roo.bootstrap.NavGroup.register(this);
4334 * Fires when the active item changes
4335 * @param {Roo.bootstrap.NavGroup} this
4336 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4337 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4344 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4355 getAutoCreate : function()
4357 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4363 if (Roo.bootstrap.version == 4) {
4364 if (this.type == 'pills') {
4365 cfg.cls = ' nav-pills';
4368 if (['tabs','pills'].indexOf(this.type)!==-1) {
4369 cfg.cls += ' nav-' + this.type
4371 if (this.type !== 'nav') {
4372 Roo.log('nav type must be nav/tabs/pills')
4374 cfg.cls += ' navbar-nav'
4378 if (this.parent() && this.parent().sidebar) {
4381 cls: 'dashboard-menu sidebar-menu'
4387 if (this.form === true) {
4390 cls: 'navbar-form form-inline'
4393 if (this.align === 'right') {
4394 cfg.cls += ' navbar-right ml-md-auto';
4396 cfg.cls += ' navbar-left';
4400 if (this.align === 'right') {
4401 cfg.cls += ' navbar-right ml-md-auto';
4403 cfg.cls += ' mr-auto';
4407 cfg.cls += ' navbar-inverse';
4415 * sets the active Navigation item
4416 * @param {Roo.bootstrap.NavItem} the new current navitem
4418 setActiveItem : function(item)
4421 Roo.each(this.navItems, function(v){
4426 v.setActive(false, true);
4433 item.setActive(true, true);
4434 this.fireEvent('changed', this, item, prev);
4439 * gets the active Navigation item
4440 * @return {Roo.bootstrap.NavItem} the current navitem
4442 getActive : function()
4446 Roo.each(this.navItems, function(v){
4457 indexOfNav : function()
4461 Roo.each(this.navItems, function(v,i){
4472 * adds a Navigation item
4473 * @param {Roo.bootstrap.NavItem} the navitem to add
4475 addItem : function(cfg)
4477 if (this.form && Roo.bootstrap.version == 4) {
4480 var cn = new Roo.bootstrap.NavItem(cfg);
4482 cn.parentId = this.id;
4483 cn.onRender(this.el, null);
4487 * register a Navigation item
4488 * @param {Roo.bootstrap.NavItem} the navitem to add
4490 register : function(item)
4492 this.navItems.push( item);
4493 item.navId = this.navId;
4498 * clear all the Navigation item
4501 clearAll : function()
4504 this.el.dom.innerHTML = '';
4507 getNavItem: function(tabId)
4510 Roo.each(this.navItems, function(e) {
4511 if (e.tabId == tabId) {
4521 setActiveNext : function()
4523 var i = this.indexOfNav(this.getActive());
4524 if (i > this.navItems.length) {
4527 this.setActiveItem(this.navItems[i+1]);
4529 setActivePrev : function()
4531 var i = this.indexOfNav(this.getActive());
4535 this.setActiveItem(this.navItems[i-1]);
4537 clearWasActive : function(except) {
4538 Roo.each(this.navItems, function(e) {
4539 if (e.tabId != except.tabId && e.was_active) {
4540 e.was_active = false;
4547 getWasActive : function ()
4550 Roo.each(this.navItems, function(e) {
4565 Roo.apply(Roo.bootstrap.NavGroup, {
4569 * register a Navigation Group
4570 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4572 register : function(navgrp)
4574 this.groups[navgrp.navId] = navgrp;
4578 * fetch a Navigation Group based on the navigation ID
4579 * @param {string} the navgroup to add
4580 * @returns {Roo.bootstrap.NavGroup} the navgroup
4582 get: function(navId) {
4583 if (typeof(this.groups[navId]) == 'undefined') {
4585 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4587 return this.groups[navId] ;
4602 * @class Roo.bootstrap.NavItem
4603 * @extends Roo.bootstrap.Component
4604 * Bootstrap Navbar.NavItem class
4605 * @cfg {String} href link to
4606 * @cfg {String} html content of button
4607 * @cfg {String} badge text inside badge
4608 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4609 * @cfg {String} glyphicon DEPRICATED - use fa
4610 * @cfg {String} icon DEPRICATED - use fa
4611 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4612 * @cfg {Boolean} active Is item active
4613 * @cfg {Boolean} disabled Is item disabled
4615 * @cfg {Boolean} preventDefault (true | false) default false
4616 * @cfg {String} tabId the tab that this item activates.
4617 * @cfg {String} tagtype (a|span) render as a href or span?
4618 * @cfg {Boolean} animateRef (true|false) link to element default false
4621 * Create a new Navbar Item
4622 * @param {Object} config The config object
4624 Roo.bootstrap.NavItem = function(config){
4625 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4630 * The raw click event for the entire grid.
4631 * @param {Roo.EventObject} e
4636 * Fires when the active item active state changes
4637 * @param {Roo.bootstrap.NavItem} this
4638 * @param {boolean} state the new state
4644 * Fires when scroll to element
4645 * @param {Roo.bootstrap.NavItem} this
4646 * @param {Object} options
4647 * @param {Roo.EventObject} e
4655 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4664 preventDefault : false,
4672 getAutoCreate : function(){
4681 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4683 if (this.disabled) {
4684 cfg.cls += ' disabled';
4687 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4691 href : this.href || "#",
4692 html: this.html || ''
4695 if (this.tagtype == 'a') {
4696 cfg.cn[0].cls = 'nav-link';
4699 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4702 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>'
4704 if(this.glyphicon) {
4705 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4710 cfg.cn[0].html += " <span class='caret'></span>";
4714 if (this.badge !== '') {
4716 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4724 onRender : function(ct, position)
4726 // Roo.log("Call onRender: " + this.xtype);
4727 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4731 return Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4735 initEvents: function()
4737 if (typeof (this.menu) != 'undefined') {
4738 this.menu.parentType = this.xtype;
4739 this.menu.triggerEl = this.el;
4740 this.menu = this.addxtype(Roo.apply({}, this.menu));
4743 this.el.select('a',true).on('click', this.onClick, this);
4745 if(this.tagtype == 'span'){
4746 this.el.select('span',true).on('click', this.onClick, this);
4749 // at this point parent should be available..
4750 this.parent().register(this);
4753 onClick : function(e)
4755 if (e.getTarget('.dropdown-menu-item')) {
4756 // did you click on a menu itemm.... - then don't trigger onclick..
4761 this.preventDefault ||
4764 Roo.log("NavItem - prevent Default?");
4768 if (this.disabled) {
4772 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4773 if (tg && tg.transition) {
4774 Roo.log("waiting for the transitionend");
4780 //Roo.log("fire event clicked");
4781 if(this.fireEvent('click', this, e) === false){
4785 if(this.tagtype == 'span'){
4789 //Roo.log(this.href);
4790 var ael = this.el.select('a',true).first();
4793 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4794 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4795 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4796 return; // ignore... - it's a 'hash' to another page.
4798 Roo.log("NavItem - prevent Default?");
4800 this.scrollToElement(e);
4804 var p = this.parent();
4806 if (['tabs','pills'].indexOf(p.type)!==-1) {
4807 if (typeof(p.setActiveItem) !== 'undefined') {
4808 p.setActiveItem(this);
4812 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4813 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4814 // remove the collapsed menu expand...
4815 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4819 isActive: function () {
4822 setActive : function(state, fire, is_was_active)
4824 if (this.active && !state && this.navId) {
4825 this.was_active = true;
4826 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4828 nv.clearWasActive(this);
4832 this.active = state;
4835 this.el.removeClass('active');
4836 } else if (!this.el.hasClass('active')) {
4837 this.el.addClass('active');
4840 this.fireEvent('changed', this, state);
4843 // show a panel if it's registered and related..
4845 if (!this.navId || !this.tabId || !state || is_was_active) {
4849 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4853 var pan = tg.getPanelByName(this.tabId);
4857 // if we can not flip to new panel - go back to old nav highlight..
4858 if (false == tg.showPanel(pan)) {
4859 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4861 var onav = nv.getWasActive();
4863 onav.setActive(true, false, true);
4872 // this should not be here...
4873 setDisabled : function(state)
4875 this.disabled = state;
4877 this.el.removeClass('disabled');
4878 } else if (!this.el.hasClass('disabled')) {
4879 this.el.addClass('disabled');
4885 * Fetch the element to display the tooltip on.
4886 * @return {Roo.Element} defaults to this.el
4888 tooltipEl : function()
4890 return this.el.select('' + this.tagtype + '', true).first();
4893 scrollToElement : function(e)
4895 var c = document.body;
4898 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4900 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4901 c = document.documentElement;
4904 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4910 var o = target.calcOffsetsTo(c);
4917 this.fireEvent('scrollto', this, options, e);
4919 Roo.get(c).scrollTo('top', options.value, true);
4932 * <span> icon </span>
4933 * <span> text </span>
4934 * <span>badge </span>
4938 * @class Roo.bootstrap.NavSidebarItem
4939 * @extends Roo.bootstrap.NavItem
4940 * Bootstrap Navbar.NavSidebarItem class
4941 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4942 * {Boolean} open is the menu open
4943 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4944 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4945 * {String} buttonSize (sm|md|lg)the extra classes for the button
4946 * {Boolean} showArrow show arrow next to the text (default true)
4948 * Create a new Navbar Button
4949 * @param {Object} config The config object
4951 Roo.bootstrap.NavSidebarItem = function(config){
4952 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4957 * The raw click event for the entire grid.
4958 * @param {Roo.EventObject} e
4963 * Fires when the active item active state changes
4964 * @param {Roo.bootstrap.NavSidebarItem} this
4965 * @param {boolean} state the new state
4973 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4975 badgeWeight : 'default',
4981 buttonWeight : 'default',
4987 getAutoCreate : function(){
4992 href : this.href || '#',
4998 if(this.buttonView){
5001 href : this.href || '#',
5002 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5015 cfg.cls += ' active';
5018 if (this.disabled) {
5019 cfg.cls += ' disabled';
5022 cfg.cls += ' open x-open';
5025 if (this.glyphicon || this.icon) {
5026 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5027 a.cn.push({ tag : 'i', cls : c }) ;
5030 if(!this.buttonView){
5033 html : this.html || ''
5040 if (this.badge !== '') {
5041 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5047 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5050 a.cls += ' dropdown-toggle treeview' ;
5056 initEvents : function()
5058 if (typeof (this.menu) != 'undefined') {
5059 this.menu.parentType = this.xtype;
5060 this.menu.triggerEl = this.el;
5061 this.menu = this.addxtype(Roo.apply({}, this.menu));
5064 this.el.on('click', this.onClick, this);
5066 if(this.badge !== ''){
5067 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5072 onClick : function(e)
5079 if(this.preventDefault){
5083 this.fireEvent('click', this);
5086 disable : function()
5088 this.setDisabled(true);
5093 this.setDisabled(false);
5096 setDisabled : function(state)
5098 if(this.disabled == state){
5102 this.disabled = state;
5105 this.el.addClass('disabled');
5109 this.el.removeClass('disabled');
5114 setActive : function(state)
5116 if(this.active == state){
5120 this.active = state;
5123 this.el.addClass('active');
5127 this.el.removeClass('active');
5132 isActive: function ()
5137 setBadge : function(str)
5143 this.badgeEl.dom.innerHTML = str;
5160 * @class Roo.bootstrap.Row
5161 * @extends Roo.bootstrap.Component
5162 * Bootstrap Row class (contains columns...)
5166 * @param {Object} config The config object
5169 Roo.bootstrap.Row = function(config){
5170 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5173 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5175 getAutoCreate : function(){
5194 * @class Roo.bootstrap.Element
5195 * @extends Roo.bootstrap.Component
5196 * Bootstrap Element class
5197 * @cfg {String} html contents of the element
5198 * @cfg {String} tag tag of the element
5199 * @cfg {String} cls class of the element
5200 * @cfg {Boolean} preventDefault (true|false) default false
5201 * @cfg {Boolean} clickable (true|false) default false
5204 * Create a new Element
5205 * @param {Object} config The config object
5208 Roo.bootstrap.Element = function(config){
5209 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5215 * When a element is chick
5216 * @param {Roo.bootstrap.Element} this
5217 * @param {Roo.EventObject} e
5223 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5228 preventDefault: false,
5231 getAutoCreate : function(){
5235 // cls: this.cls, double assign in parent class Component.js :: onRender
5242 initEvents: function()
5244 Roo.bootstrap.Element.superclass.initEvents.call(this);
5247 this.el.on('click', this.onClick, this);
5252 onClick : function(e)
5254 if(this.preventDefault){
5258 this.fireEvent('click', this, e);
5261 getValue : function()
5263 return this.el.dom.innerHTML;
5266 setValue : function(value)
5268 this.el.dom.innerHTML = value;
5283 * @class Roo.bootstrap.Pagination
5284 * @extends Roo.bootstrap.Component
5285 * Bootstrap Pagination class
5286 * @cfg {String} size xs | sm | md | lg
5287 * @cfg {Boolean} inverse false | true
5290 * Create a new Pagination
5291 * @param {Object} config The config object
5294 Roo.bootstrap.Pagination = function(config){
5295 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5298 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5304 getAutoCreate : function(){
5310 cfg.cls += ' inverse';
5316 cfg.cls += " " + this.cls;
5334 * @class Roo.bootstrap.PaginationItem
5335 * @extends Roo.bootstrap.Component
5336 * Bootstrap PaginationItem class
5337 * @cfg {String} html text
5338 * @cfg {String} href the link
5339 * @cfg {Boolean} preventDefault (true | false) default true
5340 * @cfg {Boolean} active (true | false) default false
5341 * @cfg {Boolean} disabled default false
5345 * Create a new PaginationItem
5346 * @param {Object} config The config object
5350 Roo.bootstrap.PaginationItem = function(config){
5351 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5356 * The raw click event for the entire grid.
5357 * @param {Roo.EventObject} e
5363 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5367 preventDefault: true,
5372 getAutoCreate : function(){
5378 href : this.href ? this.href : '#',
5379 html : this.html ? this.html : ''
5389 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5393 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5399 initEvents: function() {
5401 this.el.on('click', this.onClick, this);
5404 onClick : function(e)
5406 Roo.log('PaginationItem on click ');
5407 if(this.preventDefault){
5415 this.fireEvent('click', this, e);
5431 * @class Roo.bootstrap.Slider
5432 * @extends Roo.bootstrap.Component
5433 * Bootstrap Slider class
5436 * Create a new Slider
5437 * @param {Object} config The config object
5440 Roo.bootstrap.Slider = function(config){
5441 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5444 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5446 getAutoCreate : function(){
5450 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5454 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5466 * Ext JS Library 1.1.1
5467 * Copyright(c) 2006-2007, Ext JS, LLC.
5469 * Originally Released Under LGPL - original licence link has changed is not relivant.
5472 * <script type="text/javascript">
5477 * @class Roo.grid.ColumnModel
5478 * @extends Roo.util.Observable
5479 * This is the default implementation of a ColumnModel used by the Grid. It defines
5480 * the columns in the grid.
5483 var colModel = new Roo.grid.ColumnModel([
5484 {header: "Ticker", width: 60, sortable: true, locked: true},
5485 {header: "Company Name", width: 150, sortable: true},
5486 {header: "Market Cap.", width: 100, sortable: true},
5487 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5488 {header: "Employees", width: 100, sortable: true, resizable: false}
5493 * The config options listed for this class are options which may appear in each
5494 * individual column definition.
5495 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5497 * @param {Object} config An Array of column config objects. See this class's
5498 * config objects for details.
5500 Roo.grid.ColumnModel = function(config){
5502 * The config passed into the constructor
5504 this.config = config;
5507 // if no id, create one
5508 // if the column does not have a dataIndex mapping,
5509 // map it to the order it is in the config
5510 for(var i = 0, len = config.length; i < len; i++){
5512 if(typeof c.dataIndex == "undefined"){
5515 if(typeof c.renderer == "string"){
5516 c.renderer = Roo.util.Format[c.renderer];
5518 if(typeof c.id == "undefined"){
5521 if(c.editor && c.editor.xtype){
5522 c.editor = Roo.factory(c.editor, Roo.grid);
5524 if(c.editor && c.editor.isFormField){
5525 c.editor = new Roo.grid.GridEditor(c.editor);
5527 this.lookup[c.id] = c;
5531 * The width of columns which have no width specified (defaults to 100)
5534 this.defaultWidth = 100;
5537 * Default sortable of columns which have no sortable specified (defaults to false)
5540 this.defaultSortable = false;
5544 * @event widthchange
5545 * Fires when the width of a column changes.
5546 * @param {ColumnModel} this
5547 * @param {Number} columnIndex The column index
5548 * @param {Number} newWidth The new width
5550 "widthchange": true,
5552 * @event headerchange
5553 * Fires when the text of a header changes.
5554 * @param {ColumnModel} this
5555 * @param {Number} columnIndex The column index
5556 * @param {Number} newText The new header text
5558 "headerchange": true,
5560 * @event hiddenchange
5561 * Fires when a column is hidden or "unhidden".
5562 * @param {ColumnModel} this
5563 * @param {Number} columnIndex The column index
5564 * @param {Boolean} hidden true if hidden, false otherwise
5566 "hiddenchange": true,
5568 * @event columnmoved
5569 * Fires when a column is moved.
5570 * @param {ColumnModel} this
5571 * @param {Number} oldIndex
5572 * @param {Number} newIndex
5574 "columnmoved" : true,
5576 * @event columlockchange
5577 * Fires when a column's locked state is changed
5578 * @param {ColumnModel} this
5579 * @param {Number} colIndex
5580 * @param {Boolean} locked true if locked
5582 "columnlockchange" : true
5584 Roo.grid.ColumnModel.superclass.constructor.call(this);
5586 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5588 * @cfg {String} header The header text to display in the Grid view.
5591 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5592 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5593 * specified, the column's index is used as an index into the Record's data Array.
5596 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5597 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5600 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5601 * Defaults to the value of the {@link #defaultSortable} property.
5602 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5605 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5608 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5611 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5614 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5617 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5618 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5619 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5620 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5623 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5626 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5629 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5632 * @cfg {String} cursor (Optional)
5635 * @cfg {String} tooltip (Optional)
5638 * @cfg {Number} xs (Optional)
5641 * @cfg {Number} sm (Optional)
5644 * @cfg {Number} md (Optional)
5647 * @cfg {Number} lg (Optional)
5650 * Returns the id of the column at the specified index.
5651 * @param {Number} index The column index
5652 * @return {String} the id
5654 getColumnId : function(index){
5655 return this.config[index].id;
5659 * Returns the column for a specified id.
5660 * @param {String} id The column id
5661 * @return {Object} the column
5663 getColumnById : function(id){
5664 return this.lookup[id];
5669 * Returns the column for a specified dataIndex.
5670 * @param {String} dataIndex The column dataIndex
5671 * @return {Object|Boolean} the column or false if not found
5673 getColumnByDataIndex: function(dataIndex){
5674 var index = this.findColumnIndex(dataIndex);
5675 return index > -1 ? this.config[index] : false;
5679 * Returns the index for a specified column id.
5680 * @param {String} id The column id
5681 * @return {Number} the index, or -1 if not found
5683 getIndexById : function(id){
5684 for(var i = 0, len = this.config.length; i < len; i++){
5685 if(this.config[i].id == id){
5693 * Returns the index for a specified column dataIndex.
5694 * @param {String} dataIndex The column dataIndex
5695 * @return {Number} the index, or -1 if not found
5698 findColumnIndex : function(dataIndex){
5699 for(var i = 0, len = this.config.length; i < len; i++){
5700 if(this.config[i].dataIndex == dataIndex){
5708 moveColumn : function(oldIndex, newIndex){
5709 var c = this.config[oldIndex];
5710 this.config.splice(oldIndex, 1);
5711 this.config.splice(newIndex, 0, c);
5712 this.dataMap = null;
5713 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5716 isLocked : function(colIndex){
5717 return this.config[colIndex].locked === true;
5720 setLocked : function(colIndex, value, suppressEvent){
5721 if(this.isLocked(colIndex) == value){
5724 this.config[colIndex].locked = value;
5726 this.fireEvent("columnlockchange", this, colIndex, value);
5730 getTotalLockedWidth : function(){
5732 for(var i = 0; i < this.config.length; i++){
5733 if(this.isLocked(i) && !this.isHidden(i)){
5734 this.totalWidth += this.getColumnWidth(i);
5740 getLockedCount : function(){
5741 for(var i = 0, len = this.config.length; i < len; i++){
5742 if(!this.isLocked(i)){
5747 return this.config.length;
5751 * Returns the number of columns.
5754 getColumnCount : function(visibleOnly){
5755 if(visibleOnly === true){
5757 for(var i = 0, len = this.config.length; i < len; i++){
5758 if(!this.isHidden(i)){
5764 return this.config.length;
5768 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5769 * @param {Function} fn
5770 * @param {Object} scope (optional)
5771 * @return {Array} result
5773 getColumnsBy : function(fn, scope){
5775 for(var i = 0, len = this.config.length; i < len; i++){
5776 var c = this.config[i];
5777 if(fn.call(scope||this, c, i) === true){
5785 * Returns true if the specified column is sortable.
5786 * @param {Number} col The column index
5789 isSortable : function(col){
5790 if(typeof this.config[col].sortable == "undefined"){
5791 return this.defaultSortable;
5793 return this.config[col].sortable;
5797 * Returns the rendering (formatting) function defined for the column.
5798 * @param {Number} col The column index.
5799 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5801 getRenderer : function(col){
5802 if(!this.config[col].renderer){
5803 return Roo.grid.ColumnModel.defaultRenderer;
5805 return this.config[col].renderer;
5809 * Sets the rendering (formatting) function for a column.
5810 * @param {Number} col The column index
5811 * @param {Function} fn The function to use to process the cell's raw data
5812 * to return HTML markup for the grid view. The render function is called with
5813 * the following parameters:<ul>
5814 * <li>Data value.</li>
5815 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5816 * <li>css A CSS style string to apply to the table cell.</li>
5817 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5818 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5819 * <li>Row index</li>
5820 * <li>Column index</li>
5821 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5823 setRenderer : function(col, fn){
5824 this.config[col].renderer = fn;
5828 * Returns the width for the specified column.
5829 * @param {Number} col The column index
5832 getColumnWidth : function(col){
5833 return this.config[col].width * 1 || this.defaultWidth;
5837 * Sets the width for a column.
5838 * @param {Number} col The column index
5839 * @param {Number} width The new width
5841 setColumnWidth : function(col, width, suppressEvent){
5842 this.config[col].width = width;
5843 this.totalWidth = null;
5845 this.fireEvent("widthchange", this, col, width);
5850 * Returns the total width of all columns.
5851 * @param {Boolean} includeHidden True to include hidden column widths
5854 getTotalWidth : function(includeHidden){
5855 if(!this.totalWidth){
5856 this.totalWidth = 0;
5857 for(var i = 0, len = this.config.length; i < len; i++){
5858 if(includeHidden || !this.isHidden(i)){
5859 this.totalWidth += this.getColumnWidth(i);
5863 return this.totalWidth;
5867 * Returns the header for the specified column.
5868 * @param {Number} col The column index
5871 getColumnHeader : function(col){
5872 return this.config[col].header;
5876 * Sets the header for a column.
5877 * @param {Number} col The column index
5878 * @param {String} header The new header
5880 setColumnHeader : function(col, header){
5881 this.config[col].header = header;
5882 this.fireEvent("headerchange", this, col, header);
5886 * Returns the tooltip for the specified column.
5887 * @param {Number} col The column index
5890 getColumnTooltip : function(col){
5891 return this.config[col].tooltip;
5894 * Sets the tooltip for a column.
5895 * @param {Number} col The column index
5896 * @param {String} tooltip The new tooltip
5898 setColumnTooltip : function(col, tooltip){
5899 this.config[col].tooltip = tooltip;
5903 * Returns the dataIndex for the specified column.
5904 * @param {Number} col The column index
5907 getDataIndex : function(col){
5908 return this.config[col].dataIndex;
5912 * Sets the dataIndex for a column.
5913 * @param {Number} col The column index
5914 * @param {Number} dataIndex The new dataIndex
5916 setDataIndex : function(col, dataIndex){
5917 this.config[col].dataIndex = dataIndex;
5923 * Returns true if the cell is editable.
5924 * @param {Number} colIndex The column index
5925 * @param {Number} rowIndex The row index - this is nto actually used..?
5928 isCellEditable : function(colIndex, rowIndex){
5929 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5933 * Returns the editor defined for the cell/column.
5934 * return false or null to disable editing.
5935 * @param {Number} colIndex The column index
5936 * @param {Number} rowIndex The row index
5939 getCellEditor : function(colIndex, rowIndex){
5940 return this.config[colIndex].editor;
5944 * Sets if a column is editable.
5945 * @param {Number} col The column index
5946 * @param {Boolean} editable True if the column is editable
5948 setEditable : function(col, editable){
5949 this.config[col].editable = editable;
5954 * Returns true if the column is hidden.
5955 * @param {Number} colIndex The column index
5958 isHidden : function(colIndex){
5959 return this.config[colIndex].hidden;
5964 * Returns true if the column width cannot be changed
5966 isFixed : function(colIndex){
5967 return this.config[colIndex].fixed;
5971 * Returns true if the column can be resized
5974 isResizable : function(colIndex){
5975 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5978 * Sets if a column is hidden.
5979 * @param {Number} colIndex The column index
5980 * @param {Boolean} hidden True if the column is hidden
5982 setHidden : function(colIndex, hidden){
5983 this.config[colIndex].hidden = hidden;
5984 this.totalWidth = null;
5985 this.fireEvent("hiddenchange", this, colIndex, hidden);
5989 * Sets the editor for a column.
5990 * @param {Number} col The column index
5991 * @param {Object} editor The editor object
5993 setEditor : function(col, editor){
5994 this.config[col].editor = editor;
5998 Roo.grid.ColumnModel.defaultRenderer = function(value)
6000 if(typeof value == "object") {
6003 if(typeof value == "string" && value.length < 1){
6007 return String.format("{0}", value);
6010 // Alias for backwards compatibility
6011 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6014 * Ext JS Library 1.1.1
6015 * Copyright(c) 2006-2007, Ext JS, LLC.
6017 * Originally Released Under LGPL - original licence link has changed is not relivant.
6020 * <script type="text/javascript">
6024 * @class Roo.LoadMask
6025 * A simple utility class for generically masking elements while loading data. If the element being masked has
6026 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6027 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6028 * element's UpdateManager load indicator and will be destroyed after the initial load.
6030 * Create a new LoadMask
6031 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6032 * @param {Object} config The config object
6034 Roo.LoadMask = function(el, config){
6035 this.el = Roo.get(el);
6036 Roo.apply(this, config);
6038 this.store.on('beforeload', this.onBeforeLoad, this);
6039 this.store.on('load', this.onLoad, this);
6040 this.store.on('loadexception', this.onLoadException, this);
6041 this.removeMask = false;
6043 var um = this.el.getUpdateManager();
6044 um.showLoadIndicator = false; // disable the default indicator
6045 um.on('beforeupdate', this.onBeforeLoad, this);
6046 um.on('update', this.onLoad, this);
6047 um.on('failure', this.onLoad, this);
6048 this.removeMask = true;
6052 Roo.LoadMask.prototype = {
6054 * @cfg {Boolean} removeMask
6055 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6056 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6060 * The text to display in a centered loading message box (defaults to 'Loading...')
6064 * @cfg {String} msgCls
6065 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6067 msgCls : 'x-mask-loading',
6070 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6076 * Disables the mask to prevent it from being displayed
6078 disable : function(){
6079 this.disabled = true;
6083 * Enables the mask so that it can be displayed
6085 enable : function(){
6086 this.disabled = false;
6089 onLoadException : function()
6093 if (typeof(arguments[3]) != 'undefined') {
6094 Roo.MessageBox.alert("Error loading",arguments[3]);
6098 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6099 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6106 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6111 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6115 onBeforeLoad : function(){
6117 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6122 destroy : function(){
6124 this.store.un('beforeload', this.onBeforeLoad, this);
6125 this.store.un('load', this.onLoad, this);
6126 this.store.un('loadexception', this.onLoadException, this);
6128 var um = this.el.getUpdateManager();
6129 um.un('beforeupdate', this.onBeforeLoad, this);
6130 um.un('update', this.onLoad, this);
6131 um.un('failure', this.onLoad, this);
6142 * @class Roo.bootstrap.Table
6143 * @extends Roo.bootstrap.Component
6144 * Bootstrap Table class
6145 * @cfg {String} cls table class
6146 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6147 * @cfg {String} bgcolor Specifies the background color for a table
6148 * @cfg {Number} border Specifies whether the table cells should have borders or not
6149 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6150 * @cfg {Number} cellspacing Specifies the space between cells
6151 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6152 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6153 * @cfg {String} sortable Specifies that the table should be sortable
6154 * @cfg {String} summary Specifies a summary of the content of a table
6155 * @cfg {Number} width Specifies the width of a table
6156 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6158 * @cfg {boolean} striped Should the rows be alternative striped
6159 * @cfg {boolean} bordered Add borders to the table
6160 * @cfg {boolean} hover Add hover highlighting
6161 * @cfg {boolean} condensed Format condensed
6162 * @cfg {boolean} responsive Format condensed
6163 * @cfg {Boolean} loadMask (true|false) default false
6164 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6165 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6166 * @cfg {Boolean} rowSelection (true|false) default false
6167 * @cfg {Boolean} cellSelection (true|false) default false
6168 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6169 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6170 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6171 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6175 * Create a new Table
6176 * @param {Object} config The config object
6179 Roo.bootstrap.Table = function(config){
6180 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6185 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6186 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6187 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6188 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6190 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6192 this.sm.grid = this;
6193 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6194 this.sm = this.selModel;
6195 this.sm.xmodule = this.xmodule || false;
6198 if (this.cm && typeof(this.cm.config) == 'undefined') {
6199 this.colModel = new Roo.grid.ColumnModel(this.cm);
6200 this.cm = this.colModel;
6201 this.cm.xmodule = this.xmodule || false;
6204 this.store= Roo.factory(this.store, Roo.data);
6205 this.ds = this.store;
6206 this.ds.xmodule = this.xmodule || false;
6209 if (this.footer && this.store) {
6210 this.footer.dataSource = this.ds;
6211 this.footer = Roo.factory(this.footer);
6218 * Fires when a cell is clicked
6219 * @param {Roo.bootstrap.Table} this
6220 * @param {Roo.Element} el
6221 * @param {Number} rowIndex
6222 * @param {Number} columnIndex
6223 * @param {Roo.EventObject} e
6227 * @event celldblclick
6228 * Fires when a cell is double clicked
6229 * @param {Roo.bootstrap.Table} this
6230 * @param {Roo.Element} el
6231 * @param {Number} rowIndex
6232 * @param {Number} columnIndex
6233 * @param {Roo.EventObject} e
6235 "celldblclick" : true,
6238 * Fires when a row is clicked
6239 * @param {Roo.bootstrap.Table} this
6240 * @param {Roo.Element} el
6241 * @param {Number} rowIndex
6242 * @param {Roo.EventObject} e
6246 * @event rowdblclick
6247 * Fires when a row is double clicked
6248 * @param {Roo.bootstrap.Table} this
6249 * @param {Roo.Element} el
6250 * @param {Number} rowIndex
6251 * @param {Roo.EventObject} e
6253 "rowdblclick" : true,
6256 * Fires when a mouseover occur
6257 * @param {Roo.bootstrap.Table} this
6258 * @param {Roo.Element} el
6259 * @param {Number} rowIndex
6260 * @param {Number} columnIndex
6261 * @param {Roo.EventObject} e
6266 * Fires when a mouseout occur
6267 * @param {Roo.bootstrap.Table} this
6268 * @param {Roo.Element} el
6269 * @param {Number} rowIndex
6270 * @param {Number} columnIndex
6271 * @param {Roo.EventObject} e
6276 * Fires when a row is rendered, so you can change add a style to it.
6277 * @param {Roo.bootstrap.Table} this
6278 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6282 * @event rowsrendered
6283 * Fires when all the rows have been rendered
6284 * @param {Roo.bootstrap.Table} this
6286 'rowsrendered' : true,
6288 * @event contextmenu
6289 * The raw contextmenu event for the entire grid.
6290 * @param {Roo.EventObject} e
6292 "contextmenu" : true,
6294 * @event rowcontextmenu
6295 * Fires when a row is right clicked
6296 * @param {Roo.bootstrap.Table} this
6297 * @param {Number} rowIndex
6298 * @param {Roo.EventObject} e
6300 "rowcontextmenu" : true,
6302 * @event cellcontextmenu
6303 * Fires when a cell is right clicked
6304 * @param {Roo.bootstrap.Table} this
6305 * @param {Number} rowIndex
6306 * @param {Number} cellIndex
6307 * @param {Roo.EventObject} e
6309 "cellcontextmenu" : true,
6311 * @event headercontextmenu
6312 * Fires when a header is right clicked
6313 * @param {Roo.bootstrap.Table} this
6314 * @param {Number} columnIndex
6315 * @param {Roo.EventObject} e
6317 "headercontextmenu" : true
6321 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6347 rowSelection : false,
6348 cellSelection : false,
6351 // Roo.Element - the tbody
6353 // Roo.Element - thead element
6356 container: false, // used by gridpanel...
6362 auto_hide_footer : false,
6364 getAutoCreate : function()
6366 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6373 if (this.scrollBody) {
6374 cfg.cls += ' table-body-fixed';
6377 cfg.cls += ' table-striped';
6381 cfg.cls += ' table-hover';
6383 if (this.bordered) {
6384 cfg.cls += ' table-bordered';
6386 if (this.condensed) {
6387 cfg.cls += ' table-condensed';
6389 if (this.responsive) {
6390 cfg.cls += ' table-responsive';
6394 cfg.cls+= ' ' +this.cls;
6397 // this lot should be simplifed...
6410 ].forEach(function(k) {
6418 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6421 if(this.store || this.cm){
6422 if(this.headerShow){
6423 cfg.cn.push(this.renderHeader());
6426 cfg.cn.push(this.renderBody());
6428 if(this.footerShow){
6429 cfg.cn.push(this.renderFooter());
6431 // where does this come from?
6432 //cfg.cls+= ' TableGrid';
6435 return { cn : [ cfg ] };
6438 initEvents : function()
6440 if(!this.store || !this.cm){
6443 if (this.selModel) {
6444 this.selModel.initEvents();
6448 //Roo.log('initEvents with ds!!!!');
6450 this.mainBody = this.el.select('tbody', true).first();
6451 this.mainHead = this.el.select('thead', true).first();
6452 this.mainFoot = this.el.select('tfoot', true).first();
6458 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6459 e.on('click', _this.sort, _this);
6462 this.mainBody.on("click", this.onClick, this);
6463 this.mainBody.on("dblclick", this.onDblClick, this);
6465 // why is this done????? = it breaks dialogs??
6466 //this.parent().el.setStyle('position', 'relative');
6470 this.footer.parentId = this.id;
6471 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6474 this.el.select('tfoot tr td').first().addClass('hide');
6479 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6482 this.store.on('load', this.onLoad, this);
6483 this.store.on('beforeload', this.onBeforeLoad, this);
6484 this.store.on('update', this.onUpdate, this);
6485 this.store.on('add', this.onAdd, this);
6486 this.store.on("clear", this.clear, this);
6488 this.el.on("contextmenu", this.onContextMenu, this);
6490 this.mainBody.on('scroll', this.onBodyScroll, this);
6492 this.cm.on("headerchange", this.onHeaderChange, this);
6494 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6498 onContextMenu : function(e, t)
6500 this.processEvent("contextmenu", e);
6503 processEvent : function(name, e)
6505 if (name != 'touchstart' ) {
6506 this.fireEvent(name, e);
6509 var t = e.getTarget();
6511 var cell = Roo.get(t);
6517 if(cell.findParent('tfoot', false, true)){
6521 if(cell.findParent('thead', false, true)){
6523 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6524 cell = Roo.get(t).findParent('th', false, true);
6526 Roo.log("failed to find th in thead?");
6527 Roo.log(e.getTarget());
6532 var cellIndex = cell.dom.cellIndex;
6534 var ename = name == 'touchstart' ? 'click' : name;
6535 this.fireEvent("header" + ename, this, cellIndex, e);
6540 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6541 cell = Roo.get(t).findParent('td', false, true);
6543 Roo.log("failed to find th in tbody?");
6544 Roo.log(e.getTarget());
6549 var row = cell.findParent('tr', false, true);
6550 var cellIndex = cell.dom.cellIndex;
6551 var rowIndex = row.dom.rowIndex - 1;
6555 this.fireEvent("row" + name, this, rowIndex, e);
6559 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6565 onMouseover : function(e, el)
6567 var cell = Roo.get(el);
6573 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6574 cell = cell.findParent('td', false, true);
6577 var row = cell.findParent('tr', false, true);
6578 var cellIndex = cell.dom.cellIndex;
6579 var rowIndex = row.dom.rowIndex - 1; // start from 0
6581 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6585 onMouseout : function(e, el)
6587 var cell = Roo.get(el);
6593 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6594 cell = cell.findParent('td', false, true);
6597 var row = cell.findParent('tr', false, true);
6598 var cellIndex = cell.dom.cellIndex;
6599 var rowIndex = row.dom.rowIndex - 1; // start from 0
6601 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6605 onClick : function(e, el)
6607 var cell = Roo.get(el);
6609 if(!cell || (!this.cellSelection && !this.rowSelection)){
6613 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6614 cell = cell.findParent('td', false, true);
6617 if(!cell || typeof(cell) == 'undefined'){
6621 var row = cell.findParent('tr', false, true);
6623 if(!row || typeof(row) == 'undefined'){
6627 var cellIndex = cell.dom.cellIndex;
6628 var rowIndex = this.getRowIndex(row);
6630 // why??? - should these not be based on SelectionModel?
6631 if(this.cellSelection){
6632 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6635 if(this.rowSelection){
6636 this.fireEvent('rowclick', this, row, rowIndex, e);
6642 onDblClick : function(e,el)
6644 var cell = Roo.get(el);
6646 if(!cell || (!this.cellSelection && !this.rowSelection)){
6650 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6651 cell = cell.findParent('td', false, true);
6654 if(!cell || typeof(cell) == 'undefined'){
6658 var row = cell.findParent('tr', false, true);
6660 if(!row || typeof(row) == 'undefined'){
6664 var cellIndex = cell.dom.cellIndex;
6665 var rowIndex = this.getRowIndex(row);
6667 if(this.cellSelection){
6668 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6671 if(this.rowSelection){
6672 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6676 sort : function(e,el)
6678 var col = Roo.get(el);
6680 if(!col.hasClass('sortable')){
6684 var sort = col.attr('sort');
6687 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6691 this.store.sortInfo = {field : sort, direction : dir};
6694 Roo.log("calling footer first");
6695 this.footer.onClick('first');
6698 this.store.load({ params : { start : 0 } });
6702 renderHeader : function()
6710 this.totalWidth = 0;
6712 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6714 var config = cm.config[i];
6718 cls : 'x-hcol-' + i,
6720 html: cm.getColumnHeader(i)
6725 if(typeof(config.sortable) != 'undefined' && config.sortable){
6727 c.html = '<i class="glyphicon"></i>' + c.html;
6730 if(typeof(config.lgHeader) != 'undefined'){
6731 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6734 if(typeof(config.mdHeader) != 'undefined'){
6735 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6738 if(typeof(config.smHeader) != 'undefined'){
6739 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6742 if(typeof(config.xsHeader) != 'undefined'){
6743 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6750 if(typeof(config.tooltip) != 'undefined'){
6751 c.tooltip = config.tooltip;
6754 if(typeof(config.colspan) != 'undefined'){
6755 c.colspan = config.colspan;
6758 if(typeof(config.hidden) != 'undefined' && config.hidden){
6759 c.style += ' display:none;';
6762 if(typeof(config.dataIndex) != 'undefined'){
6763 c.sort = config.dataIndex;
6768 if(typeof(config.align) != 'undefined' && config.align.length){
6769 c.style += ' text-align:' + config.align + ';';
6772 if(typeof(config.width) != 'undefined'){
6773 c.style += ' width:' + config.width + 'px;';
6774 this.totalWidth += config.width;
6776 this.totalWidth += 100; // assume minimum of 100 per column?
6779 if(typeof(config.cls) != 'undefined'){
6780 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6783 ['xs','sm','md','lg'].map(function(size){
6785 if(typeof(config[size]) == 'undefined'){
6789 if (!config[size]) { // 0 = hidden
6790 c.cls += ' hidden-' + size;
6794 c.cls += ' col-' + size + '-' + config[size];
6804 renderBody : function()
6814 colspan : this.cm.getColumnCount()
6824 renderFooter : function()
6834 colspan : this.cm.getColumnCount()
6848 // Roo.log('ds onload');
6853 var ds = this.store;
6855 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6856 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6857 if (_this.store.sortInfo) {
6859 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6860 e.select('i', true).addClass(['glyphicon-arrow-up']);
6863 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6864 e.select('i', true).addClass(['glyphicon-arrow-down']);
6869 var tbody = this.mainBody;
6871 if(ds.getCount() > 0){
6872 ds.data.each(function(d,rowIndex){
6873 var row = this.renderRow(cm, ds, rowIndex);
6875 tbody.createChild(row);
6879 if(row.cellObjects.length){
6880 Roo.each(row.cellObjects, function(r){
6881 _this.renderCellObject(r);
6888 var tfoot = this.el.select('tfoot', true).first();
6890 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6892 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6894 var total = this.ds.getTotalCount();
6896 if(this.footer.pageSize < total){
6897 this.mainFoot.show();
6901 Roo.each(this.el.select('tbody td', true).elements, function(e){
6902 e.on('mouseover', _this.onMouseover, _this);
6905 Roo.each(this.el.select('tbody td', true).elements, function(e){
6906 e.on('mouseout', _this.onMouseout, _this);
6908 this.fireEvent('rowsrendered', this);
6914 onUpdate : function(ds,record)
6916 this.refreshRow(record);
6920 onRemove : function(ds, record, index, isUpdate){
6921 if(isUpdate !== true){
6922 this.fireEvent("beforerowremoved", this, index, record);
6924 var bt = this.mainBody.dom;
6926 var rows = this.el.select('tbody > tr', true).elements;
6928 if(typeof(rows[index]) != 'undefined'){
6929 bt.removeChild(rows[index].dom);
6932 // if(bt.rows[index]){
6933 // bt.removeChild(bt.rows[index]);
6936 if(isUpdate !== true){
6937 //this.stripeRows(index);
6938 //this.syncRowHeights(index, index);
6940 this.fireEvent("rowremoved", this, index, record);
6944 onAdd : function(ds, records, rowIndex)
6946 //Roo.log('on Add called');
6947 // - note this does not handle multiple adding very well..
6948 var bt = this.mainBody.dom;
6949 for (var i =0 ; i < records.length;i++) {
6950 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6951 //Roo.log(records[i]);
6952 //Roo.log(this.store.getAt(rowIndex+i));
6953 this.insertRow(this.store, rowIndex + i, false);
6960 refreshRow : function(record){
6961 var ds = this.store, index;
6962 if(typeof record == 'number'){
6964 record = ds.getAt(index);
6966 index = ds.indexOf(record);
6968 this.insertRow(ds, index, true);
6970 this.onRemove(ds, record, index+1, true);
6972 //this.syncRowHeights(index, index);
6974 this.fireEvent("rowupdated", this, index, record);
6977 insertRow : function(dm, rowIndex, isUpdate){
6980 this.fireEvent("beforerowsinserted", this, rowIndex);
6982 //var s = this.getScrollState();
6983 var row = this.renderRow(this.cm, this.store, rowIndex);
6984 // insert before rowIndex..
6985 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6989 if(row.cellObjects.length){
6990 Roo.each(row.cellObjects, function(r){
6991 _this.renderCellObject(r);
6996 this.fireEvent("rowsinserted", this, rowIndex);
6997 //this.syncRowHeights(firstRow, lastRow);
6998 //this.stripeRows(firstRow);
7005 getRowDom : function(rowIndex)
7007 var rows = this.el.select('tbody > tr', true).elements;
7009 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7012 // returns the object tree for a tr..
7015 renderRow : function(cm, ds, rowIndex)
7017 var d = ds.getAt(rowIndex);
7021 cls : 'x-row-' + rowIndex,
7025 var cellObjects = [];
7027 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7028 var config = cm.config[i];
7030 var renderer = cm.getRenderer(i);
7034 if(typeof(renderer) !== 'undefined'){
7035 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7037 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7038 // and are rendered into the cells after the row is rendered - using the id for the element.
7040 if(typeof(value) === 'object'){
7050 rowIndex : rowIndex,
7055 this.fireEvent('rowclass', this, rowcfg);
7059 cls : rowcfg.rowClass + ' x-col-' + i,
7061 html: (typeof(value) === 'object') ? '' : value
7068 if(typeof(config.colspan) != 'undefined'){
7069 td.colspan = config.colspan;
7072 if(typeof(config.hidden) != 'undefined' && config.hidden){
7073 td.style += ' display:none;';
7076 if(typeof(config.align) != 'undefined' && config.align.length){
7077 td.style += ' text-align:' + config.align + ';';
7079 if(typeof(config.valign) != 'undefined' && config.valign.length){
7080 td.style += ' vertical-align:' + config.valign + ';';
7083 if(typeof(config.width) != 'undefined'){
7084 td.style += ' width:' + config.width + 'px;';
7087 if(typeof(config.cursor) != 'undefined'){
7088 td.style += ' cursor:' + config.cursor + ';';
7091 if(typeof(config.cls) != 'undefined'){
7092 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7095 ['xs','sm','md','lg'].map(function(size){
7097 if(typeof(config[size]) == 'undefined'){
7101 if (!config[size]) { // 0 = hidden
7102 td.cls += ' hidden-' + size;
7106 td.cls += ' col-' + size + '-' + config[size];
7114 row.cellObjects = cellObjects;
7122 onBeforeLoad : function()
7131 this.el.select('tbody', true).first().dom.innerHTML = '';
7134 * Show or hide a row.
7135 * @param {Number} rowIndex to show or hide
7136 * @param {Boolean} state hide
7138 setRowVisibility : function(rowIndex, state)
7140 var bt = this.mainBody.dom;
7142 var rows = this.el.select('tbody > tr', true).elements;
7144 if(typeof(rows[rowIndex]) == 'undefined'){
7147 rows[rowIndex].dom.style.display = state ? '' : 'none';
7151 getSelectionModel : function(){
7153 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7155 return this.selModel;
7158 * Render the Roo.bootstrap object from renderder
7160 renderCellObject : function(r)
7164 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7166 var t = r.cfg.render(r.container);
7169 Roo.each(r.cfg.cn, function(c){
7171 container: t.getChildContainer(),
7174 _this.renderCellObject(child);
7179 getRowIndex : function(row)
7183 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7194 * Returns the grid's underlying element = used by panel.Grid
7195 * @return {Element} The element
7197 getGridEl : function(){
7201 * Forces a resize - used by panel.Grid
7202 * @return {Element} The element
7204 autoSize : function()
7206 //var ctr = Roo.get(this.container.dom.parentElement);
7207 var ctr = Roo.get(this.el.dom);
7209 var thd = this.getGridEl().select('thead',true).first();
7210 var tbd = this.getGridEl().select('tbody', true).first();
7211 var tfd = this.getGridEl().select('tfoot', true).first();
7213 var cw = ctr.getWidth();
7217 tbd.setSize(ctr.getWidth(),
7218 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7220 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7223 cw = Math.max(cw, this.totalWidth);
7224 this.getGridEl().select('tr',true).setWidth(cw);
7225 // resize 'expandable coloumn?
7227 return; // we doe not have a view in this design..
7230 onBodyScroll: function()
7232 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7234 this.mainHead.setStyle({
7235 'position' : 'relative',
7236 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7242 var scrollHeight = this.mainBody.dom.scrollHeight;
7244 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7246 var height = this.mainBody.getHeight();
7248 if(scrollHeight - height == scrollTop) {
7250 var total = this.ds.getTotalCount();
7252 if(this.footer.cursor + this.footer.pageSize < total){
7254 this.footer.ds.load({
7256 start : this.footer.cursor + this.footer.pageSize,
7257 limit : this.footer.pageSize
7267 onHeaderChange : function()
7269 var header = this.renderHeader();
7270 var table = this.el.select('table', true).first();
7272 this.mainHead.remove();
7273 this.mainHead = table.createChild(header, this.mainBody, false);
7276 onHiddenChange : function(colModel, colIndex, hidden)
7278 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7279 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7281 this.CSS.updateRule(thSelector, "display", "");
7282 this.CSS.updateRule(tdSelector, "display", "");
7285 this.CSS.updateRule(thSelector, "display", "none");
7286 this.CSS.updateRule(tdSelector, "display", "none");
7289 this.onHeaderChange();
7293 setColumnWidth: function(col_index, width)
7295 // width = "md-2 xs-2..."
7296 if(!this.colModel.config[col_index]) {
7300 var w = width.split(" ");
7302 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7304 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7307 for(var j = 0; j < w.length; j++) {
7313 var size_cls = w[j].split("-");
7315 if(!Number.isInteger(size_cls[1] * 1)) {
7319 if(!this.colModel.config[col_index][size_cls[0]]) {
7323 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7327 h_row[0].classList.replace(
7328 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7329 "col-"+size_cls[0]+"-"+size_cls[1]
7332 for(var i = 0; i < rows.length; i++) {
7334 var size_cls = w[j].split("-");
7336 if(!Number.isInteger(size_cls[1] * 1)) {
7340 if(!this.colModel.config[col_index][size_cls[0]]) {
7344 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7348 rows[i].classList.replace(
7349 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7350 "col-"+size_cls[0]+"-"+size_cls[1]
7354 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7369 * @class Roo.bootstrap.TableCell
7370 * @extends Roo.bootstrap.Component
7371 * Bootstrap TableCell class
7372 * @cfg {String} html cell contain text
7373 * @cfg {String} cls cell class
7374 * @cfg {String} tag cell tag (td|th) default td
7375 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7376 * @cfg {String} align Aligns the content in a cell
7377 * @cfg {String} axis Categorizes cells
7378 * @cfg {String} bgcolor Specifies the background color of a cell
7379 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7380 * @cfg {Number} colspan Specifies the number of columns a cell should span
7381 * @cfg {String} headers Specifies one or more header cells a cell is related to
7382 * @cfg {Number} height Sets the height of a cell
7383 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7384 * @cfg {Number} rowspan Sets the number of rows a cell should span
7385 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7386 * @cfg {String} valign Vertical aligns the content in a cell
7387 * @cfg {Number} width Specifies the width of a cell
7390 * Create a new TableCell
7391 * @param {Object} config The config object
7394 Roo.bootstrap.TableCell = function(config){
7395 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7398 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7418 getAutoCreate : function(){
7419 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7439 cfg.align=this.align
7445 cfg.bgcolor=this.bgcolor
7448 cfg.charoff=this.charoff
7451 cfg.colspan=this.colspan
7454 cfg.headers=this.headers
7457 cfg.height=this.height
7460 cfg.nowrap=this.nowrap
7463 cfg.rowspan=this.rowspan
7466 cfg.scope=this.scope
7469 cfg.valign=this.valign
7472 cfg.width=this.width
7491 * @class Roo.bootstrap.TableRow
7492 * @extends Roo.bootstrap.Component
7493 * Bootstrap TableRow class
7494 * @cfg {String} cls row class
7495 * @cfg {String} align Aligns the content in a table row
7496 * @cfg {String} bgcolor Specifies a background color for a table row
7497 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7498 * @cfg {String} valign Vertical aligns the content in a table row
7501 * Create a new TableRow
7502 * @param {Object} config The config object
7505 Roo.bootstrap.TableRow = function(config){
7506 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7509 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7517 getAutoCreate : function(){
7518 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7528 cfg.align = this.align;
7531 cfg.bgcolor = this.bgcolor;
7534 cfg.charoff = this.charoff;
7537 cfg.valign = this.valign;
7555 * @class Roo.bootstrap.TableBody
7556 * @extends Roo.bootstrap.Component
7557 * Bootstrap TableBody class
7558 * @cfg {String} cls element class
7559 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7560 * @cfg {String} align Aligns the content inside the element
7561 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7562 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7565 * Create a new TableBody
7566 * @param {Object} config The config object
7569 Roo.bootstrap.TableBody = function(config){
7570 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7573 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7581 getAutoCreate : function(){
7582 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7596 cfg.align = this.align;
7599 cfg.charoff = this.charoff;
7602 cfg.valign = this.valign;
7609 // initEvents : function()
7616 // this.store = Roo.factory(this.store, Roo.data);
7617 // this.store.on('load', this.onLoad, this);
7619 // this.store.load();
7623 // onLoad: function ()
7625 // this.fireEvent('load', this);
7635 * Ext JS Library 1.1.1
7636 * Copyright(c) 2006-2007, Ext JS, LLC.
7638 * Originally Released Under LGPL - original licence link has changed is not relivant.
7641 * <script type="text/javascript">
7644 // as we use this in bootstrap.
7645 Roo.namespace('Roo.form');
7647 * @class Roo.form.Action
7648 * Internal Class used to handle form actions
7650 * @param {Roo.form.BasicForm} el The form element or its id
7651 * @param {Object} config Configuration options
7656 // define the action interface
7657 Roo.form.Action = function(form, options){
7659 this.options = options || {};
7662 * Client Validation Failed
7665 Roo.form.Action.CLIENT_INVALID = 'client';
7667 * Server Validation Failed
7670 Roo.form.Action.SERVER_INVALID = 'server';
7672 * Connect to Server Failed
7675 Roo.form.Action.CONNECT_FAILURE = 'connect';
7677 * Reading Data from Server Failed
7680 Roo.form.Action.LOAD_FAILURE = 'load';
7682 Roo.form.Action.prototype = {
7684 failureType : undefined,
7685 response : undefined,
7689 run : function(options){
7694 success : function(response){
7699 handleResponse : function(response){
7703 // default connection failure
7704 failure : function(response){
7706 this.response = response;
7707 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7708 this.form.afterAction(this, false);
7711 processResponse : function(response){
7712 this.response = response;
7713 if(!response.responseText){
7716 this.result = this.handleResponse(response);
7720 // utility functions used internally
7721 getUrl : function(appendParams){
7722 var url = this.options.url || this.form.url || this.form.el.dom.action;
7724 var p = this.getParams();
7726 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7732 getMethod : function(){
7733 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7736 getParams : function(){
7737 var bp = this.form.baseParams;
7738 var p = this.options.params;
7740 if(typeof p == "object"){
7741 p = Roo.urlEncode(Roo.applyIf(p, bp));
7742 }else if(typeof p == 'string' && bp){
7743 p += '&' + Roo.urlEncode(bp);
7746 p = Roo.urlEncode(bp);
7751 createCallback : function(){
7753 success: this.success,
7754 failure: this.failure,
7756 timeout: (this.form.timeout*1000),
7757 upload: this.form.fileUpload ? this.success : undefined
7762 Roo.form.Action.Submit = function(form, options){
7763 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7766 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7769 haveProgress : false,
7770 uploadComplete : false,
7772 // uploadProgress indicator.
7773 uploadProgress : function()
7775 if (!this.form.progressUrl) {
7779 if (!this.haveProgress) {
7780 Roo.MessageBox.progress("Uploading", "Uploading");
7782 if (this.uploadComplete) {
7783 Roo.MessageBox.hide();
7787 this.haveProgress = true;
7789 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7791 var c = new Roo.data.Connection();
7793 url : this.form.progressUrl,
7798 success : function(req){
7799 //console.log(data);
7803 rdata = Roo.decode(req.responseText)
7805 Roo.log("Invalid data from server..");
7809 if (!rdata || !rdata.success) {
7811 Roo.MessageBox.alert(Roo.encode(rdata));
7814 var data = rdata.data;
7816 if (this.uploadComplete) {
7817 Roo.MessageBox.hide();
7822 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7823 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7826 this.uploadProgress.defer(2000,this);
7829 failure: function(data) {
7830 Roo.log('progress url failed ');
7841 // run get Values on the form, so it syncs any secondary forms.
7842 this.form.getValues();
7844 var o = this.options;
7845 var method = this.getMethod();
7846 var isPost = method == 'POST';
7847 if(o.clientValidation === false || this.form.isValid()){
7849 if (this.form.progressUrl) {
7850 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7851 (new Date() * 1) + '' + Math.random());
7856 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7857 form:this.form.el.dom,
7858 url:this.getUrl(!isPost),
7860 params:isPost ? this.getParams() : null,
7861 isUpload: this.form.fileUpload
7864 this.uploadProgress();
7866 }else if (o.clientValidation !== false){ // client validation failed
7867 this.failureType = Roo.form.Action.CLIENT_INVALID;
7868 this.form.afterAction(this, false);
7872 success : function(response)
7874 this.uploadComplete= true;
7875 if (this.haveProgress) {
7876 Roo.MessageBox.hide();
7880 var result = this.processResponse(response);
7881 if(result === true || result.success){
7882 this.form.afterAction(this, true);
7886 this.form.markInvalid(result.errors);
7887 this.failureType = Roo.form.Action.SERVER_INVALID;
7889 this.form.afterAction(this, false);
7891 failure : function(response)
7893 this.uploadComplete= true;
7894 if (this.haveProgress) {
7895 Roo.MessageBox.hide();
7898 this.response = response;
7899 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7900 this.form.afterAction(this, false);
7903 handleResponse : function(response){
7904 if(this.form.errorReader){
7905 var rs = this.form.errorReader.read(response);
7908 for(var i = 0, len = rs.records.length; i < len; i++) {
7909 var r = rs.records[i];
7913 if(errors.length < 1){
7917 success : rs.success,
7923 ret = Roo.decode(response.responseText);
7927 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7937 Roo.form.Action.Load = function(form, options){
7938 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7939 this.reader = this.form.reader;
7942 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7947 Roo.Ajax.request(Roo.apply(
7948 this.createCallback(), {
7949 method:this.getMethod(),
7950 url:this.getUrl(false),
7951 params:this.getParams()
7955 success : function(response){
7957 var result = this.processResponse(response);
7958 if(result === true || !result.success || !result.data){
7959 this.failureType = Roo.form.Action.LOAD_FAILURE;
7960 this.form.afterAction(this, false);
7963 this.form.clearInvalid();
7964 this.form.setValues(result.data);
7965 this.form.afterAction(this, true);
7968 handleResponse : function(response){
7969 if(this.form.reader){
7970 var rs = this.form.reader.read(response);
7971 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7973 success : rs.success,
7977 return Roo.decode(response.responseText);
7981 Roo.form.Action.ACTION_TYPES = {
7982 'load' : Roo.form.Action.Load,
7983 'submit' : Roo.form.Action.Submit
7992 * @class Roo.bootstrap.Form
7993 * @extends Roo.bootstrap.Component
7994 * Bootstrap Form class
7995 * @cfg {String} method GET | POST (default POST)
7996 * @cfg {String} labelAlign top | left (default top)
7997 * @cfg {String} align left | right - for navbars
7998 * @cfg {Boolean} loadMask load mask when submit (default true)
8003 * @param {Object} config The config object
8007 Roo.bootstrap.Form = function(config){
8009 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8011 Roo.bootstrap.Form.popover.apply();
8015 * @event clientvalidation
8016 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8017 * @param {Form} this
8018 * @param {Boolean} valid true if the form has passed client-side validation
8020 clientvalidation: true,
8022 * @event beforeaction
8023 * Fires before any action is performed. Return false to cancel the action.
8024 * @param {Form} this
8025 * @param {Action} action The action to be performed
8029 * @event actionfailed
8030 * Fires when an action fails.
8031 * @param {Form} this
8032 * @param {Action} action The action that failed
8034 actionfailed : true,
8036 * @event actioncomplete
8037 * Fires when an action is completed.
8038 * @param {Form} this
8039 * @param {Action} action The action that completed
8041 actioncomplete : true
8045 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8048 * @cfg {String} method
8049 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8054 * The URL to use for form actions if one isn't supplied in the action options.
8057 * @cfg {Boolean} fileUpload
8058 * Set to true if this form is a file upload.
8062 * @cfg {Object} baseParams
8063 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8067 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8071 * @cfg {Sting} align (left|right) for navbar forms
8076 activeAction : null,
8079 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8080 * element by passing it or its id or mask the form itself by passing in true.
8083 waitMsgTarget : false,
8088 * @cfg {Boolean} errorMask (true|false) default false
8093 * @cfg {Number} maskOffset Default 100
8098 * @cfg {Boolean} maskBody
8102 getAutoCreate : function(){
8106 method : this.method || 'POST',
8107 id : this.id || Roo.id(),
8110 if (this.parent().xtype.match(/^Nav/)) {
8111 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8115 if (this.labelAlign == 'left' ) {
8116 cfg.cls += ' form-horizontal';
8122 initEvents : function()
8124 this.el.on('submit', this.onSubmit, this);
8125 // this was added as random key presses on the form where triggering form submit.
8126 this.el.on('keypress', function(e) {
8127 if (e.getCharCode() != 13) {
8130 // we might need to allow it for textareas.. and some other items.
8131 // check e.getTarget().
8133 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8137 Roo.log("keypress blocked");
8145 onSubmit : function(e){
8150 * Returns true if client-side validation on the form is successful.
8153 isValid : function(){
8154 var items = this.getItems();
8158 items.each(function(f){
8164 Roo.log('invalid field: ' + f.name);
8168 if(!target && f.el.isVisible(true)){
8174 if(this.errorMask && !valid){
8175 Roo.bootstrap.Form.popover.mask(this, target);
8182 * Returns true if any fields in this form have changed since their original load.
8185 isDirty : function(){
8187 var items = this.getItems();
8188 items.each(function(f){
8198 * Performs a predefined action (submit or load) or custom actions you define on this form.
8199 * @param {String} actionName The name of the action type
8200 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8201 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8202 * accept other config options):
8204 Property Type Description
8205 ---------------- --------------- ----------------------------------------------------------------------------------
8206 url String The url for the action (defaults to the form's url)
8207 method String The form method to use (defaults to the form's method, or POST if not defined)
8208 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8209 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8210 validate the form on the client (defaults to false)
8212 * @return {BasicForm} this
8214 doAction : function(action, options){
8215 if(typeof action == 'string'){
8216 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8218 if(this.fireEvent('beforeaction', this, action) !== false){
8219 this.beforeAction(action);
8220 action.run.defer(100, action);
8226 beforeAction : function(action){
8227 var o = action.options;
8232 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8234 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8237 // not really supported yet.. ??
8239 //if(this.waitMsgTarget === true){
8240 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8241 //}else if(this.waitMsgTarget){
8242 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8243 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8245 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8251 afterAction : function(action, success){
8252 this.activeAction = null;
8253 var o = action.options;
8258 Roo.get(document.body).unmask();
8264 //if(this.waitMsgTarget === true){
8265 // this.el.unmask();
8266 //}else if(this.waitMsgTarget){
8267 // this.waitMsgTarget.unmask();
8269 // Roo.MessageBox.updateProgress(1);
8270 // Roo.MessageBox.hide();
8277 Roo.callback(o.success, o.scope, [this, action]);
8278 this.fireEvent('actioncomplete', this, action);
8282 // failure condition..
8283 // we have a scenario where updates need confirming.
8284 // eg. if a locking scenario exists..
8285 // we look for { errors : { needs_confirm : true }} in the response.
8287 (typeof(action.result) != 'undefined') &&
8288 (typeof(action.result.errors) != 'undefined') &&
8289 (typeof(action.result.errors.needs_confirm) != 'undefined')
8292 Roo.log("not supported yet");
8295 Roo.MessageBox.confirm(
8296 "Change requires confirmation",
8297 action.result.errorMsg,
8302 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8312 Roo.callback(o.failure, o.scope, [this, action]);
8313 // show an error message if no failed handler is set..
8314 if (!this.hasListener('actionfailed')) {
8315 Roo.log("need to add dialog support");
8317 Roo.MessageBox.alert("Error",
8318 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8319 action.result.errorMsg :
8320 "Saving Failed, please check your entries or try again"
8325 this.fireEvent('actionfailed', this, action);
8330 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8331 * @param {String} id The value to search for
8334 findField : function(id){
8335 var items = this.getItems();
8336 var field = items.get(id);
8338 items.each(function(f){
8339 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8346 return field || null;
8349 * Mark fields in this form invalid in bulk.
8350 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8351 * @return {BasicForm} this
8353 markInvalid : function(errors){
8354 if(errors instanceof Array){
8355 for(var i = 0, len = errors.length; i < len; i++){
8356 var fieldError = errors[i];
8357 var f = this.findField(fieldError.id);
8359 f.markInvalid(fieldError.msg);
8365 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8366 field.markInvalid(errors[id]);
8370 //Roo.each(this.childForms || [], function (f) {
8371 // f.markInvalid(errors);
8378 * Set values for fields in this form in bulk.
8379 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8380 * @return {BasicForm} this
8382 setValues : function(values){
8383 if(values instanceof Array){ // array of objects
8384 for(var i = 0, len = values.length; i < len; i++){
8386 var f = this.findField(v.id);
8388 f.setValue(v.value);
8389 if(this.trackResetOnLoad){
8390 f.originalValue = f.getValue();
8394 }else{ // object hash
8397 if(typeof values[id] != 'function' && (field = this.findField(id))){
8399 if (field.setFromData &&
8401 field.displayField &&
8402 // combos' with local stores can
8403 // be queried via setValue()
8404 // to set their value..
8405 (field.store && !field.store.isLocal)
8409 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8410 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8411 field.setFromData(sd);
8413 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8415 field.setFromData(values);
8418 field.setValue(values[id]);
8422 if(this.trackResetOnLoad){
8423 field.originalValue = field.getValue();
8429 //Roo.each(this.childForms || [], function (f) {
8430 // f.setValues(values);
8437 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8438 * they are returned as an array.
8439 * @param {Boolean} asString
8442 getValues : function(asString){
8443 //if (this.childForms) {
8444 // copy values from the child forms
8445 // Roo.each(this.childForms, function (f) {
8446 // this.setValues(f.getValues());
8452 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8453 if(asString === true){
8456 return Roo.urlDecode(fs);
8460 * Returns the fields in this form as an object with key/value pairs.
8461 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8464 getFieldValues : function(with_hidden)
8466 var items = this.getItems();
8468 items.each(function(f){
8474 var v = f.getValue();
8476 if (f.inputType =='radio') {
8477 if (typeof(ret[f.getName()]) == 'undefined') {
8478 ret[f.getName()] = ''; // empty..
8481 if (!f.el.dom.checked) {
8489 if(f.xtype == 'MoneyField'){
8490 ret[f.currencyName] = f.getCurrency();
8493 // not sure if this supported any more..
8494 if ((typeof(v) == 'object') && f.getRawValue) {
8495 v = f.getRawValue() ; // dates..
8497 // combo boxes where name != hiddenName...
8498 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8499 ret[f.name] = f.getRawValue();
8501 ret[f.getName()] = v;
8508 * Clears all invalid messages in this form.
8509 * @return {BasicForm} this
8511 clearInvalid : function(){
8512 var items = this.getItems();
8514 items.each(function(f){
8523 * @return {BasicForm} this
8526 var items = this.getItems();
8527 items.each(function(f){
8531 Roo.each(this.childForms || [], function (f) {
8539 getItems : function()
8541 var r=new Roo.util.MixedCollection(false, function(o){
8542 return o.id || (o.id = Roo.id());
8544 var iter = function(el) {
8551 Roo.each(el.items,function(e) {
8560 hideFields : function(items)
8562 Roo.each(items, function(i){
8564 var f = this.findField(i);
8575 showFields : function(items)
8577 Roo.each(items, function(i){
8579 var f = this.findField(i);
8592 Roo.apply(Roo.bootstrap.Form, {
8619 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8620 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8621 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8622 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8625 this.maskEl.top.enableDisplayMode("block");
8626 this.maskEl.left.enableDisplayMode("block");
8627 this.maskEl.bottom.enableDisplayMode("block");
8628 this.maskEl.right.enableDisplayMode("block");
8630 this.toolTip = new Roo.bootstrap.Tooltip({
8631 cls : 'roo-form-error-popover',
8633 'left' : ['r-l', [-2,0], 'right'],
8634 'right' : ['l-r', [2,0], 'left'],
8635 'bottom' : ['tl-bl', [0,2], 'top'],
8636 'top' : [ 'bl-tl', [0,-2], 'bottom']
8640 this.toolTip.render(Roo.get(document.body));
8642 this.toolTip.el.enableDisplayMode("block");
8644 Roo.get(document.body).on('click', function(){
8648 Roo.get(document.body).on('touchstart', function(){
8652 this.isApplied = true
8655 mask : function(form, target)
8659 this.target = target;
8661 if(!this.form.errorMask || !target.el){
8665 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8667 Roo.log(scrollable);
8669 var ot = this.target.el.calcOffsetsTo(scrollable);
8671 var scrollTo = ot[1] - this.form.maskOffset;
8673 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8675 scrollable.scrollTo('top', scrollTo);
8677 var box = this.target.el.getBox();
8679 var zIndex = Roo.bootstrap.Modal.zIndex++;
8682 this.maskEl.top.setStyle('position', 'absolute');
8683 this.maskEl.top.setStyle('z-index', zIndex);
8684 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8685 this.maskEl.top.setLeft(0);
8686 this.maskEl.top.setTop(0);
8687 this.maskEl.top.show();
8689 this.maskEl.left.setStyle('position', 'absolute');
8690 this.maskEl.left.setStyle('z-index', zIndex);
8691 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8692 this.maskEl.left.setLeft(0);
8693 this.maskEl.left.setTop(box.y - this.padding);
8694 this.maskEl.left.show();
8696 this.maskEl.bottom.setStyle('position', 'absolute');
8697 this.maskEl.bottom.setStyle('z-index', zIndex);
8698 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8699 this.maskEl.bottom.setLeft(0);
8700 this.maskEl.bottom.setTop(box.bottom + this.padding);
8701 this.maskEl.bottom.show();
8703 this.maskEl.right.setStyle('position', 'absolute');
8704 this.maskEl.right.setStyle('z-index', zIndex);
8705 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8706 this.maskEl.right.setLeft(box.right + this.padding);
8707 this.maskEl.right.setTop(box.y - this.padding);
8708 this.maskEl.right.show();
8710 this.toolTip.bindEl = this.target.el;
8712 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8714 var tip = this.target.blankText;
8716 if(this.target.getValue() !== '' ) {
8718 if (this.target.invalidText.length) {
8719 tip = this.target.invalidText;
8720 } else if (this.target.regexText.length){
8721 tip = this.target.regexText;
8725 this.toolTip.show(tip);
8727 this.intervalID = window.setInterval(function() {
8728 Roo.bootstrap.Form.popover.unmask();
8731 window.onwheel = function(){ return false;};
8733 (function(){ this.isMasked = true; }).defer(500, this);
8739 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8743 this.maskEl.top.setStyle('position', 'absolute');
8744 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8745 this.maskEl.top.hide();
8747 this.maskEl.left.setStyle('position', 'absolute');
8748 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8749 this.maskEl.left.hide();
8751 this.maskEl.bottom.setStyle('position', 'absolute');
8752 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8753 this.maskEl.bottom.hide();
8755 this.maskEl.right.setStyle('position', 'absolute');
8756 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8757 this.maskEl.right.hide();
8759 this.toolTip.hide();
8761 this.toolTip.el.hide();
8763 window.onwheel = function(){ return true;};
8765 if(this.intervalID){
8766 window.clearInterval(this.intervalID);
8767 this.intervalID = false;
8770 this.isMasked = false;
8780 * Ext JS Library 1.1.1
8781 * Copyright(c) 2006-2007, Ext JS, LLC.
8783 * Originally Released Under LGPL - original licence link has changed is not relivant.
8786 * <script type="text/javascript">
8789 * @class Roo.form.VTypes
8790 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8793 Roo.form.VTypes = function(){
8794 // closure these in so they are only created once.
8795 var alpha = /^[a-zA-Z_]+$/;
8796 var alphanum = /^[a-zA-Z0-9_]+$/;
8797 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8798 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8800 // All these messages and functions are configurable
8803 * The function used to validate email addresses
8804 * @param {String} value The email address
8806 'email' : function(v){
8807 return email.test(v);
8810 * The error text to display when the email validation function returns false
8813 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8815 * The keystroke filter mask to be applied on email input
8818 'emailMask' : /[a-z0-9_\.\-@]/i,
8821 * The function used to validate URLs
8822 * @param {String} value The URL
8824 'url' : function(v){
8828 * The error text to display when the url validation function returns false
8831 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8834 * The function used to validate alpha values
8835 * @param {String} value The value
8837 'alpha' : function(v){
8838 return alpha.test(v);
8841 * The error text to display when the alpha validation function returns false
8844 'alphaText' : 'This field should only contain letters and _',
8846 * The keystroke filter mask to be applied on alpha input
8849 'alphaMask' : /[a-z_]/i,
8852 * The function used to validate alphanumeric values
8853 * @param {String} value The value
8855 'alphanum' : function(v){
8856 return alphanum.test(v);
8859 * The error text to display when the alphanumeric validation function returns false
8862 'alphanumText' : 'This field should only contain letters, numbers and _',
8864 * The keystroke filter mask to be applied on alphanumeric input
8867 'alphanumMask' : /[a-z0-9_]/i
8877 * @class Roo.bootstrap.Input
8878 * @extends Roo.bootstrap.Component
8879 * Bootstrap Input class
8880 * @cfg {Boolean} disabled is it disabled
8881 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8882 * @cfg {String} name name of the input
8883 * @cfg {string} fieldLabel - the label associated
8884 * @cfg {string} placeholder - placeholder to put in text.
8885 * @cfg {string} before - input group add on before
8886 * @cfg {string} after - input group add on after
8887 * @cfg {string} size - (lg|sm) or leave empty..
8888 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8889 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8890 * @cfg {Number} md colspan out of 12 for computer-sized screens
8891 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8892 * @cfg {string} value default value of the input
8893 * @cfg {Number} labelWidth set the width of label
8894 * @cfg {Number} labellg set the width of label (1-12)
8895 * @cfg {Number} labelmd set the width of label (1-12)
8896 * @cfg {Number} labelsm set the width of label (1-12)
8897 * @cfg {Number} labelxs set the width of label (1-12)
8898 * @cfg {String} labelAlign (top|left)
8899 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8900 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8901 * @cfg {String} indicatorpos (left|right) default left
8902 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8903 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8905 * @cfg {String} align (left|center|right) Default left
8906 * @cfg {Boolean} forceFeedback (true|false) Default false
8909 * Create a new Input
8910 * @param {Object} config The config object
8913 Roo.bootstrap.Input = function(config){
8915 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8920 * Fires when this field receives input focus.
8921 * @param {Roo.form.Field} this
8926 * Fires when this field loses input focus.
8927 * @param {Roo.form.Field} this
8932 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8933 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8934 * @param {Roo.form.Field} this
8935 * @param {Roo.EventObject} e The event object
8940 * Fires just before the field blurs if the field value has changed.
8941 * @param {Roo.form.Field} this
8942 * @param {Mixed} newValue The new value
8943 * @param {Mixed} oldValue The original value
8948 * Fires after the field has been marked as invalid.
8949 * @param {Roo.form.Field} this
8950 * @param {String} msg The validation message
8955 * Fires after the field has been validated with no errors.
8956 * @param {Roo.form.Field} this
8961 * Fires after the key up
8962 * @param {Roo.form.Field} this
8963 * @param {Roo.EventObject} e The event Object
8969 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8971 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8972 automatic validation (defaults to "keyup").
8974 validationEvent : "keyup",
8976 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8978 validateOnBlur : true,
8980 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8982 validationDelay : 250,
8984 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8986 focusClass : "x-form-focus", // not needed???
8990 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8992 invalidClass : "has-warning",
8995 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8997 validClass : "has-success",
9000 * @cfg {Boolean} hasFeedback (true|false) default true
9005 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9007 invalidFeedbackClass : "glyphicon-warning-sign",
9010 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9012 validFeedbackClass : "glyphicon-ok",
9015 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9017 selectOnFocus : false,
9020 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9024 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9029 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9031 disableKeyFilter : false,
9034 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9038 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9042 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9044 blankText : "Please complete this mandatory field",
9047 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9051 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9053 maxLength : Number.MAX_VALUE,
9055 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9057 minLengthText : "The minimum length for this field is {0}",
9059 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9061 maxLengthText : "The maximum length for this field is {0}",
9065 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9066 * If available, this function will be called only after the basic validators all return true, and will be passed the
9067 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9071 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9072 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9073 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9077 * @cfg {String} regexText -- Depricated - use Invalid Text
9082 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9088 autocomplete: false,
9107 formatedValue : false,
9108 forceFeedback : false,
9110 indicatorpos : 'left',
9120 parentLabelAlign : function()
9123 while (parent.parent()) {
9124 parent = parent.parent();
9125 if (typeof(parent.labelAlign) !='undefined') {
9126 return parent.labelAlign;
9133 getAutoCreate : function()
9135 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9141 if(this.inputType != 'hidden'){
9142 cfg.cls = 'form-group' //input-group
9148 type : this.inputType,
9150 cls : 'form-control',
9151 placeholder : this.placeholder || '',
9152 autocomplete : this.autocomplete || 'new-password'
9155 if(this.capture.length){
9156 input.capture = this.capture;
9159 if(this.accept.length){
9160 input.accept = this.accept + "/*";
9164 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9167 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9168 input.maxLength = this.maxLength;
9171 if (this.disabled) {
9172 input.disabled=true;
9175 if (this.readOnly) {
9176 input.readonly=true;
9180 input.name = this.name;
9184 input.cls += ' input-' + this.size;
9188 ['xs','sm','md','lg'].map(function(size){
9189 if (settings[size]) {
9190 cfg.cls += ' col-' + size + '-' + settings[size];
9194 var inputblock = input;
9198 cls: 'glyphicon form-control-feedback'
9201 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9204 cls : 'has-feedback',
9212 if (this.before || this.after) {
9215 cls : 'input-group',
9219 if (this.before && typeof(this.before) == 'string') {
9221 inputblock.cn.push({
9223 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9227 if (this.before && typeof(this.before) == 'object') {
9228 this.before = Roo.factory(this.before);
9230 inputblock.cn.push({
9232 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9233 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9237 inputblock.cn.push(input);
9239 if (this.after && typeof(this.after) == 'string') {
9240 inputblock.cn.push({
9242 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9246 if (this.after && typeof(this.after) == 'object') {
9247 this.after = Roo.factory(this.after);
9249 inputblock.cn.push({
9251 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9252 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9256 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9257 inputblock.cls += ' has-feedback';
9258 inputblock.cn.push(feedback);
9263 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9264 tooltip : 'This field is required'
9266 if (Roo.bootstrap.version == 4) {
9269 style : 'display-none'
9272 if (align ==='left' && this.fieldLabel.length) {
9274 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9281 cls : 'control-label col-form-label',
9282 html : this.fieldLabel
9293 var labelCfg = cfg.cn[1];
9294 var contentCfg = cfg.cn[2];
9296 if(this.indicatorpos == 'right'){
9301 cls : 'control-label col-form-label',
9305 html : this.fieldLabel
9319 labelCfg = cfg.cn[0];
9320 contentCfg = cfg.cn[1];
9324 if(this.labelWidth > 12){
9325 labelCfg.style = "width: " + this.labelWidth + 'px';
9328 if(this.labelWidth < 13 && this.labelmd == 0){
9329 this.labelmd = this.labelWidth;
9332 if(this.labellg > 0){
9333 labelCfg.cls += ' col-lg-' + this.labellg;
9334 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9337 if(this.labelmd > 0){
9338 labelCfg.cls += ' col-md-' + this.labelmd;
9339 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9342 if(this.labelsm > 0){
9343 labelCfg.cls += ' col-sm-' + this.labelsm;
9344 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9347 if(this.labelxs > 0){
9348 labelCfg.cls += ' col-xs-' + this.labelxs;
9349 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9353 } else if ( this.fieldLabel.length) {
9358 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9359 tooltip : 'This field is required'
9363 //cls : 'input-group-addon',
9364 html : this.fieldLabel
9372 if(this.indicatorpos == 'right'){
9377 //cls : 'input-group-addon',
9378 html : this.fieldLabel
9383 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9384 tooltip : 'This field is required'
9404 if (this.parentType === 'Navbar' && this.parent().bar) {
9405 cfg.cls += ' navbar-form';
9408 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9409 // on BS4 we do this only if not form
9410 cfg.cls += ' navbar-form';
9418 * return the real input element.
9420 inputEl: function ()
9422 return this.el.select('input.form-control',true).first();
9425 tooltipEl : function()
9427 return this.inputEl();
9430 indicatorEl : function()
9432 if (Roo.bootstrap.version == 4) {
9433 return false; // not enabled in v4 yet.
9436 var indicator = this.el.select('i.roo-required-indicator',true).first();
9446 setDisabled : function(v)
9448 var i = this.inputEl().dom;
9450 i.removeAttribute('disabled');
9454 i.setAttribute('disabled','true');
9456 initEvents : function()
9459 this.inputEl().on("keydown" , this.fireKey, this);
9460 this.inputEl().on("focus", this.onFocus, this);
9461 this.inputEl().on("blur", this.onBlur, this);
9463 this.inputEl().relayEvent('keyup', this);
9465 this.indicator = this.indicatorEl();
9468 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9471 // reference to original value for reset
9472 this.originalValue = this.getValue();
9473 //Roo.form.TextField.superclass.initEvents.call(this);
9474 if(this.validationEvent == 'keyup'){
9475 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9476 this.inputEl().on('keyup', this.filterValidation, this);
9478 else if(this.validationEvent !== false){
9479 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9482 if(this.selectOnFocus){
9483 this.on("focus", this.preFocus, this);
9486 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9487 this.inputEl().on("keypress", this.filterKeys, this);
9489 this.inputEl().relayEvent('keypress', this);
9492 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9493 this.el.on("click", this.autoSize, this);
9496 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9497 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9500 if (typeof(this.before) == 'object') {
9501 this.before.render(this.el.select('.roo-input-before',true).first());
9503 if (typeof(this.after) == 'object') {
9504 this.after.render(this.el.select('.roo-input-after',true).first());
9507 this.inputEl().on('change', this.onChange, this);
9510 filterValidation : function(e){
9511 if(!e.isNavKeyPress()){
9512 this.validationTask.delay(this.validationDelay);
9516 * Validates the field value
9517 * @return {Boolean} True if the value is valid, else false
9519 validate : function(){
9520 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9521 if(this.disabled || this.validateValue(this.getRawValue())){
9532 * Validates a value according to the field's validation rules and marks the field as invalid
9533 * if the validation fails
9534 * @param {Mixed} value The value to validate
9535 * @return {Boolean} True if the value is valid, else false
9537 validateValue : function(value)
9539 if(this.getVisibilityEl().hasClass('hidden')){
9543 if(value.length < 1) { // if it's blank
9544 if(this.allowBlank){
9550 if(value.length < this.minLength){
9553 if(value.length > this.maxLength){
9557 var vt = Roo.form.VTypes;
9558 if(!vt[this.vtype](value, this)){
9562 if(typeof this.validator == "function"){
9563 var msg = this.validator(value);
9567 if (typeof(msg) == 'string') {
9568 this.invalidText = msg;
9572 if(this.regex && !this.regex.test(value)){
9580 fireKey : function(e){
9581 //Roo.log('field ' + e.getKey());
9582 if(e.isNavKeyPress()){
9583 this.fireEvent("specialkey", this, e);
9586 focus : function (selectText){
9588 this.inputEl().focus();
9589 if(selectText === true){
9590 this.inputEl().dom.select();
9596 onFocus : function(){
9597 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9598 // this.el.addClass(this.focusClass);
9601 this.hasFocus = true;
9602 this.startValue = this.getValue();
9603 this.fireEvent("focus", this);
9607 beforeBlur : Roo.emptyFn,
9611 onBlur : function(){
9613 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9614 //this.el.removeClass(this.focusClass);
9616 this.hasFocus = false;
9617 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9620 var v = this.getValue();
9621 if(String(v) !== String(this.startValue)){
9622 this.fireEvent('change', this, v, this.startValue);
9624 this.fireEvent("blur", this);
9627 onChange : function(e)
9629 var v = this.getValue();
9630 if(String(v) !== String(this.startValue)){
9631 this.fireEvent('change', this, v, this.startValue);
9637 * Resets the current field value to the originally loaded value and clears any validation messages
9640 this.setValue(this.originalValue);
9644 * Returns the name of the field
9645 * @return {Mixed} name The name field
9647 getName: function(){
9651 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9652 * @return {Mixed} value The field value
9654 getValue : function(){
9656 var v = this.inputEl().getValue();
9661 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9662 * @return {Mixed} value The field value
9664 getRawValue : function(){
9665 var v = this.inputEl().getValue();
9671 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9672 * @param {Mixed} value The value to set
9674 setRawValue : function(v){
9675 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9678 selectText : function(start, end){
9679 var v = this.getRawValue();
9681 start = start === undefined ? 0 : start;
9682 end = end === undefined ? v.length : end;
9683 var d = this.inputEl().dom;
9684 if(d.setSelectionRange){
9685 d.setSelectionRange(start, end);
9686 }else if(d.createTextRange){
9687 var range = d.createTextRange();
9688 range.moveStart("character", start);
9689 range.moveEnd("character", v.length-end);
9696 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9697 * @param {Mixed} value The value to set
9699 setValue : function(v){
9702 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9708 processValue : function(value){
9709 if(this.stripCharsRe){
9710 var newValue = value.replace(this.stripCharsRe, '');
9711 if(newValue !== value){
9712 this.setRawValue(newValue);
9719 preFocus : function(){
9721 if(this.selectOnFocus){
9722 this.inputEl().dom.select();
9725 filterKeys : function(e){
9727 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9730 var c = e.getCharCode(), cc = String.fromCharCode(c);
9731 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9734 if(!this.maskRe.test(cc)){
9739 * Clear any invalid styles/messages for this field
9741 clearInvalid : function(){
9743 if(!this.el || this.preventMark){ // not rendered
9748 this.el.removeClass(this.invalidClass);
9750 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9752 var feedback = this.el.select('.form-control-feedback', true).first();
9755 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9761 this.indicator.removeClass('visible');
9762 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9765 this.fireEvent('valid', this);
9769 * Mark this field as valid
9771 markValid : function()
9773 if(!this.el || this.preventMark){ // not rendered...
9777 this.el.removeClass([this.invalidClass, this.validClass]);
9779 var feedback = this.el.select('.form-control-feedback', true).first();
9782 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9786 this.indicator.removeClass('visible');
9787 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9794 if(this.allowBlank && !this.getRawValue().length){
9798 this.el.addClass(this.validClass);
9800 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9802 var feedback = this.el.select('.form-control-feedback', true).first();
9805 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9806 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9811 this.fireEvent('valid', this);
9815 * Mark this field as invalid
9816 * @param {String} msg The validation message
9818 markInvalid : function(msg)
9820 if(!this.el || this.preventMark){ // not rendered
9824 this.el.removeClass([this.invalidClass, this.validClass]);
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]);
9836 if(this.allowBlank && !this.getRawValue().length){
9841 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9842 this.indicator.addClass('visible');
9845 this.el.addClass(this.invalidClass);
9847 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9849 var feedback = this.el.select('.form-control-feedback', true).first();
9852 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9854 if(this.getValue().length || this.forceFeedback){
9855 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9862 this.fireEvent('invalid', this, msg);
9865 SafariOnKeyDown : function(event)
9867 // this is a workaround for a password hang bug on chrome/ webkit.
9868 if (this.inputEl().dom.type != 'password') {
9872 var isSelectAll = false;
9874 if(this.inputEl().dom.selectionEnd > 0){
9875 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9877 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9878 event.preventDefault();
9883 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9885 event.preventDefault();
9886 // this is very hacky as keydown always get's upper case.
9888 var cc = String.fromCharCode(event.getCharCode());
9889 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9893 adjustWidth : function(tag, w){
9894 tag = tag.toLowerCase();
9895 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9896 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9900 if(tag == 'textarea'){
9903 }else if(Roo.isOpera){
9907 if(tag == 'textarea'){
9915 setFieldLabel : function(v)
9921 if(this.indicatorEl()){
9922 var ar = this.el.select('label > span',true);
9924 if (ar.elements.length) {
9925 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9926 this.fieldLabel = v;
9930 var br = this.el.select('label',true);
9932 if(br.elements.length) {
9933 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9934 this.fieldLabel = v;
9938 Roo.log('Cannot Found any of label > span || label in input');
9942 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9943 this.fieldLabel = v;
9958 * @class Roo.bootstrap.TextArea
9959 * @extends Roo.bootstrap.Input
9960 * Bootstrap TextArea class
9961 * @cfg {Number} cols Specifies the visible width of a text area
9962 * @cfg {Number} rows Specifies the visible number of lines in a text area
9963 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9964 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9965 * @cfg {string} html text
9968 * Create a new TextArea
9969 * @param {Object} config The config object
9972 Roo.bootstrap.TextArea = function(config){
9973 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9977 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9987 getAutoCreate : function(){
9989 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9995 if(this.inputType != 'hidden'){
9996 cfg.cls = 'form-group' //input-group
10004 value : this.value || '',
10005 html: this.html || '',
10006 cls : 'form-control',
10007 placeholder : this.placeholder || ''
10011 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10012 input.maxLength = this.maxLength;
10016 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10020 input.cols = this.cols;
10023 if (this.readOnly) {
10024 input.readonly = true;
10028 input.name = this.name;
10032 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10036 ['xs','sm','md','lg'].map(function(size){
10037 if (settings[size]) {
10038 cfg.cls += ' col-' + size + '-' + settings[size];
10042 var inputblock = input;
10044 if(this.hasFeedback && !this.allowBlank){
10048 cls: 'glyphicon form-control-feedback'
10052 cls : 'has-feedback',
10061 if (this.before || this.after) {
10064 cls : 'input-group',
10068 inputblock.cn.push({
10070 cls : 'input-group-addon',
10075 inputblock.cn.push(input);
10077 if(this.hasFeedback && !this.allowBlank){
10078 inputblock.cls += ' has-feedback';
10079 inputblock.cn.push(feedback);
10083 inputblock.cn.push({
10085 cls : 'input-group-addon',
10092 if (align ==='left' && this.fieldLabel.length) {
10097 cls : 'control-label',
10098 html : this.fieldLabel
10109 if(this.labelWidth > 12){
10110 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10113 if(this.labelWidth < 13 && this.labelmd == 0){
10114 this.labelmd = this.labelWidth;
10117 if(this.labellg > 0){
10118 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10119 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10122 if(this.labelmd > 0){
10123 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10124 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10127 if(this.labelsm > 0){
10128 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10129 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10132 if(this.labelxs > 0){
10133 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10134 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10137 } else if ( this.fieldLabel.length) {
10142 //cls : 'input-group-addon',
10143 html : this.fieldLabel
10161 if (this.disabled) {
10162 input.disabled=true;
10169 * return the real textarea element.
10171 inputEl: function ()
10173 return this.el.select('textarea.form-control',true).first();
10177 * Clear any invalid styles/messages for this field
10179 clearInvalid : function()
10182 if(!this.el || this.preventMark){ // not rendered
10186 var label = this.el.select('label', true).first();
10187 var icon = this.el.select('i.fa-star', true).first();
10193 this.el.removeClass(this.invalidClass);
10195 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10197 var feedback = this.el.select('.form-control-feedback', true).first();
10200 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10205 this.fireEvent('valid', this);
10209 * Mark this field as valid
10211 markValid : function()
10213 if(!this.el || this.preventMark){ // not rendered
10217 this.el.removeClass([this.invalidClass, this.validClass]);
10219 var feedback = this.el.select('.form-control-feedback', true).first();
10222 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10225 if(this.disabled || this.allowBlank){
10229 var label = this.el.select('label', true).first();
10230 var icon = this.el.select('i.fa-star', true).first();
10236 this.el.addClass(this.validClass);
10238 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10240 var feedback = this.el.select('.form-control-feedback', true).first();
10243 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10244 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10249 this.fireEvent('valid', this);
10253 * Mark this field as invalid
10254 * @param {String} msg The validation message
10256 markInvalid : function(msg)
10258 if(!this.el || this.preventMark){ // not rendered
10262 this.el.removeClass([this.invalidClass, this.validClass]);
10264 var feedback = this.el.select('.form-control-feedback', true).first();
10267 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10270 if(this.disabled || this.allowBlank){
10274 var label = this.el.select('label', true).first();
10275 var icon = this.el.select('i.fa-star', true).first();
10277 if(!this.getValue().length && label && !icon){
10278 this.el.createChild({
10280 cls : 'text-danger fa fa-lg fa-star',
10281 tooltip : 'This field is required',
10282 style : 'margin-right:5px;'
10286 this.el.addClass(this.invalidClass);
10288 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10290 var feedback = this.el.select('.form-control-feedback', true).first();
10293 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10295 if(this.getValue().length || this.forceFeedback){
10296 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10303 this.fireEvent('invalid', this, msg);
10311 * trigger field - base class for combo..
10316 * @class Roo.bootstrap.TriggerField
10317 * @extends Roo.bootstrap.Input
10318 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10319 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10320 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10321 * for which you can provide a custom implementation. For example:
10323 var trigger = new Roo.bootstrap.TriggerField();
10324 trigger.onTriggerClick = myTriggerFn;
10325 trigger.applyTo('my-field');
10328 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10329 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10330 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10331 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10332 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10335 * Create a new TriggerField.
10336 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10337 * to the base TextField)
10339 Roo.bootstrap.TriggerField = function(config){
10340 this.mimicing = false;
10341 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10344 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10346 * @cfg {String} triggerClass A CSS class to apply to the trigger
10349 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10354 * @cfg {Boolean} removable (true|false) special filter default false
10358 /** @cfg {Boolean} grow @hide */
10359 /** @cfg {Number} growMin @hide */
10360 /** @cfg {Number} growMax @hide */
10366 autoSize: Roo.emptyFn,
10370 deferHeight : true,
10373 actionMode : 'wrap',
10378 getAutoCreate : function(){
10380 var align = this.labelAlign || this.parentLabelAlign();
10385 cls: 'form-group' //input-group
10392 type : this.inputType,
10393 cls : 'form-control',
10394 autocomplete: 'new-password',
10395 placeholder : this.placeholder || ''
10399 input.name = this.name;
10402 input.cls += ' input-' + this.size;
10405 if (this.disabled) {
10406 input.disabled=true;
10409 var inputblock = input;
10411 if(this.hasFeedback && !this.allowBlank){
10415 cls: 'glyphicon form-control-feedback'
10418 if(this.removable && !this.editable && !this.tickable){
10420 cls : 'has-feedback',
10426 cls : 'roo-combo-removable-btn close'
10433 cls : 'has-feedback',
10442 if(this.removable && !this.editable && !this.tickable){
10444 cls : 'roo-removable',
10450 cls : 'roo-combo-removable-btn close'
10457 if (this.before || this.after) {
10460 cls : 'input-group',
10464 inputblock.cn.push({
10466 cls : 'input-group-addon input-group-prepend input-group-text',
10471 inputblock.cn.push(input);
10473 if(this.hasFeedback && !this.allowBlank){
10474 inputblock.cls += ' has-feedback';
10475 inputblock.cn.push(feedback);
10479 inputblock.cn.push({
10481 cls : 'input-group-addon input-group-append input-group-text',
10490 var ibwrap = inputblock;
10495 cls: 'roo-select2-choices',
10499 cls: 'roo-select2-search-field',
10511 cls: 'roo-select2-container input-group',
10516 cls: 'form-hidden-field'
10522 if(!this.multiple && this.showToggleBtn){
10528 if (this.caret != false) {
10531 cls: 'fa fa-' + this.caret
10538 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10543 cls: 'combobox-clear',
10557 combobox.cls += ' roo-select2-container-multi';
10561 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10562 tooltip : 'This field is required'
10564 if (Roo.bootstrap.version == 4) {
10567 style : 'display:none'
10572 if (align ==='left' && this.fieldLabel.length) {
10574 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10581 cls : 'control-label',
10582 html : this.fieldLabel
10594 var labelCfg = cfg.cn[1];
10595 var contentCfg = cfg.cn[2];
10597 if(this.indicatorpos == 'right'){
10602 cls : 'control-label',
10606 html : this.fieldLabel
10620 labelCfg = cfg.cn[0];
10621 contentCfg = cfg.cn[1];
10624 if(this.labelWidth > 12){
10625 labelCfg.style = "width: " + this.labelWidth + 'px';
10628 if(this.labelWidth < 13 && this.labelmd == 0){
10629 this.labelmd = this.labelWidth;
10632 if(this.labellg > 0){
10633 labelCfg.cls += ' col-lg-' + this.labellg;
10634 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10637 if(this.labelmd > 0){
10638 labelCfg.cls += ' col-md-' + this.labelmd;
10639 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10642 if(this.labelsm > 0){
10643 labelCfg.cls += ' col-sm-' + this.labelsm;
10644 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10647 if(this.labelxs > 0){
10648 labelCfg.cls += ' col-xs-' + this.labelxs;
10649 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10652 } else if ( this.fieldLabel.length) {
10653 // Roo.log(" label");
10658 //cls : 'input-group-addon',
10659 html : this.fieldLabel
10667 if(this.indicatorpos == 'right'){
10675 html : this.fieldLabel
10689 // Roo.log(" no label && no align");
10696 ['xs','sm','md','lg'].map(function(size){
10697 if (settings[size]) {
10698 cfg.cls += ' col-' + size + '-' + settings[size];
10709 onResize : function(w, h){
10710 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10711 // if(typeof w == 'number'){
10712 // var x = w - this.trigger.getWidth();
10713 // this.inputEl().setWidth(this.adjustWidth('input', x));
10714 // this.trigger.setStyle('left', x+'px');
10719 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10722 getResizeEl : function(){
10723 return this.inputEl();
10727 getPositionEl : function(){
10728 return this.inputEl();
10732 alignErrorIcon : function(){
10733 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10737 initEvents : function(){
10741 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10742 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10743 if(!this.multiple && this.showToggleBtn){
10744 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10745 if(this.hideTrigger){
10746 this.trigger.setDisplayed(false);
10748 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10752 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10755 if(this.removable && !this.editable && !this.tickable){
10756 var close = this.closeTriggerEl();
10759 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10760 close.on('click', this.removeBtnClick, this, close);
10764 //this.trigger.addClassOnOver('x-form-trigger-over');
10765 //this.trigger.addClassOnClick('x-form-trigger-click');
10768 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10772 closeTriggerEl : function()
10774 var close = this.el.select('.roo-combo-removable-btn', true).first();
10775 return close ? close : false;
10778 removeBtnClick : function(e, h, el)
10780 e.preventDefault();
10782 if(this.fireEvent("remove", this) !== false){
10784 this.fireEvent("afterremove", this)
10788 createList : function()
10790 this.list = Roo.get(document.body).createChild({
10791 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10792 cls: 'typeahead typeahead-long dropdown-menu',
10793 style: 'display:none'
10796 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10801 initTrigger : function(){
10806 onDestroy : function(){
10808 this.trigger.removeAllListeners();
10809 // this.trigger.remove();
10812 // this.wrap.remove();
10814 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10818 onFocus : function(){
10819 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10821 if(!this.mimicing){
10822 this.wrap.addClass('x-trigger-wrap-focus');
10823 this.mimicing = true;
10824 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10825 if(this.monitorTab){
10826 this.el.on("keydown", this.checkTab, this);
10833 checkTab : function(e){
10834 if(e.getKey() == e.TAB){
10835 this.triggerBlur();
10840 onBlur : function(){
10845 mimicBlur : function(e, t){
10847 if(!this.wrap.contains(t) && this.validateBlur()){
10848 this.triggerBlur();
10854 triggerBlur : function(){
10855 this.mimicing = false;
10856 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10857 if(this.monitorTab){
10858 this.el.un("keydown", this.checkTab, this);
10860 //this.wrap.removeClass('x-trigger-wrap-focus');
10861 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10865 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10866 validateBlur : function(e, t){
10871 onDisable : function(){
10872 this.inputEl().dom.disabled = true;
10873 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10875 // this.wrap.addClass('x-item-disabled');
10880 onEnable : function(){
10881 this.inputEl().dom.disabled = false;
10882 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10884 // this.el.removeClass('x-item-disabled');
10889 onShow : function(){
10890 var ae = this.getActionEl();
10893 ae.dom.style.display = '';
10894 ae.dom.style.visibility = 'visible';
10900 onHide : function(){
10901 var ae = this.getActionEl();
10902 ae.dom.style.display = 'none';
10906 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10907 * by an implementing function.
10909 * @param {EventObject} e
10911 onTriggerClick : Roo.emptyFn
10915 * Ext JS Library 1.1.1
10916 * Copyright(c) 2006-2007, Ext JS, LLC.
10918 * Originally Released Under LGPL - original licence link has changed is not relivant.
10921 * <script type="text/javascript">
10926 * @class Roo.data.SortTypes
10928 * Defines the default sorting (casting?) comparison functions used when sorting data.
10930 Roo.data.SortTypes = {
10932 * Default sort that does nothing
10933 * @param {Mixed} s The value being converted
10934 * @return {Mixed} The comparison value
10936 none : function(s){
10941 * The regular expression used to strip tags
10945 stripTagsRE : /<\/?[^>]+>/gi,
10948 * Strips all HTML tags to sort on text only
10949 * @param {Mixed} s The value being converted
10950 * @return {String} The comparison value
10952 asText : function(s){
10953 return String(s).replace(this.stripTagsRE, "");
10957 * Strips all HTML tags to sort on text only - Case insensitive
10958 * @param {Mixed} s The value being converted
10959 * @return {String} The comparison value
10961 asUCText : function(s){
10962 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10966 * Case insensitive string
10967 * @param {Mixed} s The value being converted
10968 * @return {String} The comparison value
10970 asUCString : function(s) {
10971 return String(s).toUpperCase();
10976 * @param {Mixed} s The value being converted
10977 * @return {Number} The comparison value
10979 asDate : function(s) {
10983 if(s instanceof Date){
10984 return s.getTime();
10986 return Date.parse(String(s));
10991 * @param {Mixed} s The value being converted
10992 * @return {Float} The comparison value
10994 asFloat : function(s) {
10995 var val = parseFloat(String(s).replace(/,/g, ""));
11004 * @param {Mixed} s The value being converted
11005 * @return {Number} The comparison value
11007 asInt : function(s) {
11008 var val = parseInt(String(s).replace(/,/g, ""));
11016 * Ext JS Library 1.1.1
11017 * Copyright(c) 2006-2007, Ext JS, LLC.
11019 * Originally Released Under LGPL - original licence link has changed is not relivant.
11022 * <script type="text/javascript">
11026 * @class Roo.data.Record
11027 * Instances of this class encapsulate both record <em>definition</em> information, and record
11028 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11029 * to access Records cached in an {@link Roo.data.Store} object.<br>
11031 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11032 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11035 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11037 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11038 * {@link #create}. The parameters are the same.
11039 * @param {Array} data An associative Array of data values keyed by the field name.
11040 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11041 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11042 * not specified an integer id is generated.
11044 Roo.data.Record = function(data, id){
11045 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11050 * Generate a constructor for a specific record layout.
11051 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11052 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11053 * Each field definition object may contain the following properties: <ul>
11054 * <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,
11055 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11056 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11057 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11058 * is being used, then this is a string containing the javascript expression to reference the data relative to
11059 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11060 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11061 * this may be omitted.</p></li>
11062 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11063 * <ul><li>auto (Default, implies no conversion)</li>
11068 * <li>date</li></ul></p></li>
11069 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11070 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11071 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11072 * by the Reader into an object that will be stored in the Record. It is passed the
11073 * following parameters:<ul>
11074 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11076 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11078 * <br>usage:<br><pre><code>
11079 var TopicRecord = Roo.data.Record.create(
11080 {name: 'title', mapping: 'topic_title'},
11081 {name: 'author', mapping: 'username'},
11082 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11083 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11084 {name: 'lastPoster', mapping: 'user2'},
11085 {name: 'excerpt', mapping: 'post_text'}
11088 var myNewRecord = new TopicRecord({
11089 title: 'Do my job please',
11092 lastPost: new Date(),
11093 lastPoster: 'Animal',
11094 excerpt: 'No way dude!'
11096 myStore.add(myNewRecord);
11101 Roo.data.Record.create = function(o){
11102 var f = function(){
11103 f.superclass.constructor.apply(this, arguments);
11105 Roo.extend(f, Roo.data.Record);
11106 var p = f.prototype;
11107 p.fields = new Roo.util.MixedCollection(false, function(field){
11110 for(var i = 0, len = o.length; i < len; i++){
11111 p.fields.add(new Roo.data.Field(o[i]));
11113 f.getField = function(name){
11114 return p.fields.get(name);
11119 Roo.data.Record.AUTO_ID = 1000;
11120 Roo.data.Record.EDIT = 'edit';
11121 Roo.data.Record.REJECT = 'reject';
11122 Roo.data.Record.COMMIT = 'commit';
11124 Roo.data.Record.prototype = {
11126 * Readonly flag - true if this record has been modified.
11135 join : function(store){
11136 this.store = store;
11140 * Set the named field to the specified value.
11141 * @param {String} name The name of the field to set.
11142 * @param {Object} value The value to set the field to.
11144 set : function(name, value){
11145 if(this.data[name] == value){
11149 if(!this.modified){
11150 this.modified = {};
11152 if(typeof this.modified[name] == 'undefined'){
11153 this.modified[name] = this.data[name];
11155 this.data[name] = value;
11156 if(!this.editing && this.store){
11157 this.store.afterEdit(this);
11162 * Get the value of the named field.
11163 * @param {String} name The name of the field to get the value of.
11164 * @return {Object} The value of the field.
11166 get : function(name){
11167 return this.data[name];
11171 beginEdit : function(){
11172 this.editing = true;
11173 this.modified = {};
11177 cancelEdit : function(){
11178 this.editing = false;
11179 delete this.modified;
11183 endEdit : function(){
11184 this.editing = false;
11185 if(this.dirty && this.store){
11186 this.store.afterEdit(this);
11191 * Usually called by the {@link Roo.data.Store} which owns the Record.
11192 * Rejects all changes made to the Record since either creation, or the last commit operation.
11193 * Modified fields are reverted to their original values.
11195 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11196 * of reject operations.
11198 reject : function(){
11199 var m = this.modified;
11201 if(typeof m[n] != "function"){
11202 this.data[n] = m[n];
11205 this.dirty = false;
11206 delete this.modified;
11207 this.editing = false;
11209 this.store.afterReject(this);
11214 * Usually called by the {@link Roo.data.Store} which owns the Record.
11215 * Commits all changes made to the Record since either creation, or the last commit operation.
11217 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11218 * of commit operations.
11220 commit : function(){
11221 this.dirty = false;
11222 delete this.modified;
11223 this.editing = false;
11225 this.store.afterCommit(this);
11230 hasError : function(){
11231 return this.error != null;
11235 clearError : function(){
11240 * Creates a copy of this record.
11241 * @param {String} id (optional) A new record id if you don't want to use this record's id
11244 copy : function(newId) {
11245 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11249 * Ext JS Library 1.1.1
11250 * Copyright(c) 2006-2007, Ext JS, LLC.
11252 * Originally Released Under LGPL - original licence link has changed is not relivant.
11255 * <script type="text/javascript">
11261 * @class Roo.data.Store
11262 * @extends Roo.util.Observable
11263 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11264 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11266 * 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
11267 * has no knowledge of the format of the data returned by the Proxy.<br>
11269 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11270 * instances from the data object. These records are cached and made available through accessor functions.
11272 * Creates a new Store.
11273 * @param {Object} config A config object containing the objects needed for the Store to access data,
11274 * and read the data into Records.
11276 Roo.data.Store = function(config){
11277 this.data = new Roo.util.MixedCollection(false);
11278 this.data.getKey = function(o){
11281 this.baseParams = {};
11283 this.paramNames = {
11288 "multisort" : "_multisort"
11291 if(config && config.data){
11292 this.inlineData = config.data;
11293 delete config.data;
11296 Roo.apply(this, config);
11298 if(this.reader){ // reader passed
11299 this.reader = Roo.factory(this.reader, Roo.data);
11300 this.reader.xmodule = this.xmodule || false;
11301 if(!this.recordType){
11302 this.recordType = this.reader.recordType;
11304 if(this.reader.onMetaChange){
11305 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11309 if(this.recordType){
11310 this.fields = this.recordType.prototype.fields;
11312 this.modified = [];
11316 * @event datachanged
11317 * Fires when the data cache has changed, and a widget which is using this Store
11318 * as a Record cache should refresh its view.
11319 * @param {Store} this
11321 datachanged : true,
11323 * @event metachange
11324 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11325 * @param {Store} this
11326 * @param {Object} meta The JSON metadata
11331 * Fires when Records have been added to the Store
11332 * @param {Store} this
11333 * @param {Roo.data.Record[]} records The array of Records added
11334 * @param {Number} index The index at which the record(s) were added
11339 * Fires when a Record has been removed from the Store
11340 * @param {Store} this
11341 * @param {Roo.data.Record} record The Record that was removed
11342 * @param {Number} index The index at which the record was removed
11347 * Fires when a Record has been updated
11348 * @param {Store} this
11349 * @param {Roo.data.Record} record The Record that was updated
11350 * @param {String} operation The update operation being performed. Value may be one of:
11352 Roo.data.Record.EDIT
11353 Roo.data.Record.REJECT
11354 Roo.data.Record.COMMIT
11360 * Fires when the data cache has been cleared.
11361 * @param {Store} this
11365 * @event beforeload
11366 * Fires before a request is made for a new data object. If the beforeload handler returns false
11367 * the load action will be canceled.
11368 * @param {Store} this
11369 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11373 * @event beforeloadadd
11374 * Fires after a new set of Records has been loaded.
11375 * @param {Store} this
11376 * @param {Roo.data.Record[]} records The Records that were loaded
11377 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11379 beforeloadadd : true,
11382 * Fires after a new set of Records has been loaded, before they are added to the store.
11383 * @param {Store} this
11384 * @param {Roo.data.Record[]} records The Records that were loaded
11385 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11386 * @params {Object} return from reader
11390 * @event loadexception
11391 * Fires if an exception occurs in the Proxy during loading.
11392 * Called with the signature of the Proxy's "loadexception" event.
11393 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11396 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11397 * @param {Object} load options
11398 * @param {Object} jsonData from your request (normally this contains the Exception)
11400 loadexception : true
11404 this.proxy = Roo.factory(this.proxy, Roo.data);
11405 this.proxy.xmodule = this.xmodule || false;
11406 this.relayEvents(this.proxy, ["loadexception"]);
11408 this.sortToggle = {};
11409 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11411 Roo.data.Store.superclass.constructor.call(this);
11413 if(this.inlineData){
11414 this.loadData(this.inlineData);
11415 delete this.inlineData;
11419 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11421 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11422 * without a remote query - used by combo/forms at present.
11426 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11429 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11432 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11433 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11436 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11437 * on any HTTP request
11440 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11443 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11447 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11448 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11450 remoteSort : false,
11453 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11454 * loaded or when a record is removed. (defaults to false).
11456 pruneModifiedRecords : false,
11459 lastOptions : null,
11462 * Add Records to the Store and fires the add event.
11463 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11465 add : function(records){
11466 records = [].concat(records);
11467 for(var i = 0, len = records.length; i < len; i++){
11468 records[i].join(this);
11470 var index = this.data.length;
11471 this.data.addAll(records);
11472 this.fireEvent("add", this, records, index);
11476 * Remove a Record from the Store and fires the remove event.
11477 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11479 remove : function(record){
11480 var index = this.data.indexOf(record);
11481 this.data.removeAt(index);
11483 if(this.pruneModifiedRecords){
11484 this.modified.remove(record);
11486 this.fireEvent("remove", this, record, index);
11490 * Remove all Records from the Store and fires the clear event.
11492 removeAll : function(){
11494 if(this.pruneModifiedRecords){
11495 this.modified = [];
11497 this.fireEvent("clear", this);
11501 * Inserts Records to the Store at the given index and fires the add event.
11502 * @param {Number} index The start index at which to insert the passed Records.
11503 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11505 insert : function(index, records){
11506 records = [].concat(records);
11507 for(var i = 0, len = records.length; i < len; i++){
11508 this.data.insert(index, records[i]);
11509 records[i].join(this);
11511 this.fireEvent("add", this, records, index);
11515 * Get the index within the cache of the passed Record.
11516 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11517 * @return {Number} The index of the passed Record. Returns -1 if not found.
11519 indexOf : function(record){
11520 return this.data.indexOf(record);
11524 * Get the index within the cache of the Record with the passed id.
11525 * @param {String} id The id of the Record to find.
11526 * @return {Number} The index of the Record. Returns -1 if not found.
11528 indexOfId : function(id){
11529 return this.data.indexOfKey(id);
11533 * Get the Record with the specified id.
11534 * @param {String} id The id of the Record to find.
11535 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11537 getById : function(id){
11538 return this.data.key(id);
11542 * Get the Record at the specified index.
11543 * @param {Number} index The index of the Record to find.
11544 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11546 getAt : function(index){
11547 return this.data.itemAt(index);
11551 * Returns a range of Records between specified indices.
11552 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11553 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11554 * @return {Roo.data.Record[]} An array of Records
11556 getRange : function(start, end){
11557 return this.data.getRange(start, end);
11561 storeOptions : function(o){
11562 o = Roo.apply({}, o);
11565 this.lastOptions = o;
11569 * Loads the Record cache from the configured Proxy using the configured Reader.
11571 * If using remote paging, then the first load call must specify the <em>start</em>
11572 * and <em>limit</em> properties in the options.params property to establish the initial
11573 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11575 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11576 * and this call will return before the new data has been loaded. Perform any post-processing
11577 * in a callback function, or in a "load" event handler.</strong>
11579 * @param {Object} options An object containing properties which control loading options:<ul>
11580 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11581 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11582 * passed the following arguments:<ul>
11583 * <li>r : Roo.data.Record[]</li>
11584 * <li>options: Options object from the load call</li>
11585 * <li>success: Boolean success indicator</li></ul></li>
11586 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11587 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11590 load : function(options){
11591 options = options || {};
11592 if(this.fireEvent("beforeload", this, options) !== false){
11593 this.storeOptions(options);
11594 var p = Roo.apply(options.params || {}, this.baseParams);
11595 // if meta was not loaded from remote source.. try requesting it.
11596 if (!this.reader.metaFromRemote) {
11597 p._requestMeta = 1;
11599 if(this.sortInfo && this.remoteSort){
11600 var pn = this.paramNames;
11601 p[pn["sort"]] = this.sortInfo.field;
11602 p[pn["dir"]] = this.sortInfo.direction;
11604 if (this.multiSort) {
11605 var pn = this.paramNames;
11606 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11609 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11614 * Reloads the Record cache from the configured Proxy using the configured Reader and
11615 * the options from the last load operation performed.
11616 * @param {Object} options (optional) An object containing properties which may override the options
11617 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11618 * the most recently used options are reused).
11620 reload : function(options){
11621 this.load(Roo.applyIf(options||{}, this.lastOptions));
11625 // Called as a callback by the Reader during a load operation.
11626 loadRecords : function(o, options, success){
11627 if(!o || success === false){
11628 if(success !== false){
11629 this.fireEvent("load", this, [], options, o);
11631 if(options.callback){
11632 options.callback.call(options.scope || this, [], options, false);
11636 // if data returned failure - throw an exception.
11637 if (o.success === false) {
11638 // show a message if no listener is registered.
11639 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11640 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11642 // loadmask wil be hooked into this..
11643 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11646 var r = o.records, t = o.totalRecords || r.length;
11648 this.fireEvent("beforeloadadd", this, r, options, o);
11650 if(!options || options.add !== true){
11651 if(this.pruneModifiedRecords){
11652 this.modified = [];
11654 for(var i = 0, len = r.length; i < len; i++){
11658 this.data = this.snapshot;
11659 delete this.snapshot;
11662 this.data.addAll(r);
11663 this.totalLength = t;
11665 this.fireEvent("datachanged", this);
11667 this.totalLength = Math.max(t, this.data.length+r.length);
11671 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11673 var e = new Roo.data.Record({});
11675 e.set(this.parent.displayField, this.parent.emptyTitle);
11676 e.set(this.parent.valueField, '');
11681 this.fireEvent("load", this, r, options, o);
11682 if(options.callback){
11683 options.callback.call(options.scope || this, r, options, true);
11689 * Loads data from a passed data block. A Reader which understands the format of the data
11690 * must have been configured in the constructor.
11691 * @param {Object} data The data block from which to read the Records. The format of the data expected
11692 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11693 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11695 loadData : function(o, append){
11696 var r = this.reader.readRecords(o);
11697 this.loadRecords(r, {add: append}, true);
11701 * Gets the number of cached records.
11703 * <em>If using paging, this may not be the total size of the dataset. If the data object
11704 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11705 * the data set size</em>
11707 getCount : function(){
11708 return this.data.length || 0;
11712 * Gets the total number of records in the dataset as returned by the server.
11714 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11715 * the dataset size</em>
11717 getTotalCount : function(){
11718 return this.totalLength || 0;
11722 * Returns the sort state of the Store as an object with two properties:
11724 field {String} The name of the field by which the Records are sorted
11725 direction {String} The sort order, "ASC" or "DESC"
11728 getSortState : function(){
11729 return this.sortInfo;
11733 applySort : function(){
11734 if(this.sortInfo && !this.remoteSort){
11735 var s = this.sortInfo, f = s.field;
11736 var st = this.fields.get(f).sortType;
11737 var fn = function(r1, r2){
11738 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11739 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11741 this.data.sort(s.direction, fn);
11742 if(this.snapshot && this.snapshot != this.data){
11743 this.snapshot.sort(s.direction, fn);
11749 * Sets the default sort column and order to be used by the next load operation.
11750 * @param {String} fieldName The name of the field to sort by.
11751 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11753 setDefaultSort : function(field, dir){
11754 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11758 * Sort the Records.
11759 * If remote sorting is used, the sort is performed on the server, and the cache is
11760 * reloaded. If local sorting is used, the cache is sorted internally.
11761 * @param {String} fieldName The name of the field to sort by.
11762 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11764 sort : function(fieldName, dir){
11765 var f = this.fields.get(fieldName);
11767 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11769 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11770 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11775 this.sortToggle[f.name] = dir;
11776 this.sortInfo = {field: f.name, direction: dir};
11777 if(!this.remoteSort){
11779 this.fireEvent("datachanged", this);
11781 this.load(this.lastOptions);
11786 * Calls the specified function for each of the Records in the cache.
11787 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11788 * Returning <em>false</em> aborts and exits the iteration.
11789 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11791 each : function(fn, scope){
11792 this.data.each(fn, scope);
11796 * Gets all records modified since the last commit. Modified records are persisted across load operations
11797 * (e.g., during paging).
11798 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11800 getModifiedRecords : function(){
11801 return this.modified;
11805 createFilterFn : function(property, value, anyMatch){
11806 if(!value.exec){ // not a regex
11807 value = String(value);
11808 if(value.length == 0){
11811 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11813 return function(r){
11814 return value.test(r.data[property]);
11819 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11820 * @param {String} property A field on your records
11821 * @param {Number} start The record index to start at (defaults to 0)
11822 * @param {Number} end The last record index to include (defaults to length - 1)
11823 * @return {Number} The sum
11825 sum : function(property, start, end){
11826 var rs = this.data.items, v = 0;
11827 start = start || 0;
11828 end = (end || end === 0) ? end : rs.length-1;
11830 for(var i = start; i <= end; i++){
11831 v += (rs[i].data[property] || 0);
11837 * Filter the records by a specified property.
11838 * @param {String} field A field on your records
11839 * @param {String/RegExp} value Either a string that the field
11840 * should start with or a RegExp to test against the field
11841 * @param {Boolean} anyMatch True to match any part not just the beginning
11843 filter : function(property, value, anyMatch){
11844 var fn = this.createFilterFn(property, value, anyMatch);
11845 return fn ? this.filterBy(fn) : this.clearFilter();
11849 * Filter by a function. The specified function will be called with each
11850 * record in this data source. If the function returns true the record is included,
11851 * otherwise it is filtered.
11852 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11853 * @param {Object} scope (optional) The scope of the function (defaults to this)
11855 filterBy : function(fn, scope){
11856 this.snapshot = this.snapshot || this.data;
11857 this.data = this.queryBy(fn, scope||this);
11858 this.fireEvent("datachanged", this);
11862 * Query the records by a specified property.
11863 * @param {String} field A field on your records
11864 * @param {String/RegExp} value Either a string that the field
11865 * should start with or a RegExp to test against the field
11866 * @param {Boolean} anyMatch True to match any part not just the beginning
11867 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11869 query : function(property, value, anyMatch){
11870 var fn = this.createFilterFn(property, value, anyMatch);
11871 return fn ? this.queryBy(fn) : this.data.clone();
11875 * Query by a function. The specified function will be called with each
11876 * record in this data source. If the function returns true the record is included
11878 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11879 * @param {Object} scope (optional) The scope of the function (defaults to this)
11880 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11882 queryBy : function(fn, scope){
11883 var data = this.snapshot || this.data;
11884 return data.filterBy(fn, scope||this);
11888 * Collects unique values for a particular dataIndex from this store.
11889 * @param {String} dataIndex The property to collect
11890 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11891 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11892 * @return {Array} An array of the unique values
11894 collect : function(dataIndex, allowNull, bypassFilter){
11895 var d = (bypassFilter === true && this.snapshot) ?
11896 this.snapshot.items : this.data.items;
11897 var v, sv, r = [], l = {};
11898 for(var i = 0, len = d.length; i < len; i++){
11899 v = d[i].data[dataIndex];
11901 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11910 * Revert to a view of the Record cache with no filtering applied.
11911 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11913 clearFilter : function(suppressEvent){
11914 if(this.snapshot && this.snapshot != this.data){
11915 this.data = this.snapshot;
11916 delete this.snapshot;
11917 if(suppressEvent !== true){
11918 this.fireEvent("datachanged", this);
11924 afterEdit : function(record){
11925 if(this.modified.indexOf(record) == -1){
11926 this.modified.push(record);
11928 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11932 afterReject : function(record){
11933 this.modified.remove(record);
11934 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11938 afterCommit : function(record){
11939 this.modified.remove(record);
11940 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11944 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11945 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11947 commitChanges : function(){
11948 var m = this.modified.slice(0);
11949 this.modified = [];
11950 for(var i = 0, len = m.length; i < len; i++){
11956 * Cancel outstanding changes on all changed records.
11958 rejectChanges : function(){
11959 var m = this.modified.slice(0);
11960 this.modified = [];
11961 for(var i = 0, len = m.length; i < len; i++){
11966 onMetaChange : function(meta, rtype, o){
11967 this.recordType = rtype;
11968 this.fields = rtype.prototype.fields;
11969 delete this.snapshot;
11970 this.sortInfo = meta.sortInfo || this.sortInfo;
11971 this.modified = [];
11972 this.fireEvent('metachange', this, this.reader.meta);
11975 moveIndex : function(data, type)
11977 var index = this.indexOf(data);
11979 var newIndex = index + type;
11983 this.insert(newIndex, data);
11988 * Ext JS Library 1.1.1
11989 * Copyright(c) 2006-2007, Ext JS, LLC.
11991 * Originally Released Under LGPL - original licence link has changed is not relivant.
11994 * <script type="text/javascript">
11998 * @class Roo.data.SimpleStore
11999 * @extends Roo.data.Store
12000 * Small helper class to make creating Stores from Array data easier.
12001 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12002 * @cfg {Array} fields An array of field definition objects, or field name strings.
12003 * @cfg {Array} data The multi-dimensional array of data
12005 * @param {Object} config
12007 Roo.data.SimpleStore = function(config){
12008 Roo.data.SimpleStore.superclass.constructor.call(this, {
12010 reader: new Roo.data.ArrayReader({
12013 Roo.data.Record.create(config.fields)
12015 proxy : new Roo.data.MemoryProxy(config.data)
12019 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12021 * Ext JS Library 1.1.1
12022 * Copyright(c) 2006-2007, Ext JS, LLC.
12024 * Originally Released Under LGPL - original licence link has changed is not relivant.
12027 * <script type="text/javascript">
12032 * @extends Roo.data.Store
12033 * @class Roo.data.JsonStore
12034 * Small helper class to make creating Stores for JSON data easier. <br/>
12036 var store = new Roo.data.JsonStore({
12037 url: 'get-images.php',
12039 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12042 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12043 * JsonReader and HttpProxy (unless inline data is provided).</b>
12044 * @cfg {Array} fields An array of field definition objects, or field name strings.
12046 * @param {Object} config
12048 Roo.data.JsonStore = function(c){
12049 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12050 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12051 reader: new Roo.data.JsonReader(c, c.fields)
12054 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
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 Roo.data.Field = function(config){
12067 if(typeof config == "string"){
12068 config = {name: config};
12070 Roo.apply(this, config);
12073 this.type = "auto";
12076 var st = Roo.data.SortTypes;
12077 // named sortTypes are supported, here we look them up
12078 if(typeof this.sortType == "string"){
12079 this.sortType = st[this.sortType];
12082 // set default sortType for strings and dates
12083 if(!this.sortType){
12086 this.sortType = st.asUCString;
12089 this.sortType = st.asDate;
12092 this.sortType = st.none;
12097 var stripRe = /[\$,%]/g;
12099 // prebuilt conversion function for this field, instead of
12100 // switching every time we're reading a value
12102 var cv, dateFormat = this.dateFormat;
12107 cv = function(v){ return v; };
12110 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12114 return v !== undefined && v !== null && v !== '' ?
12115 parseInt(String(v).replace(stripRe, ""), 10) : '';
12120 return v !== undefined && v !== null && v !== '' ?
12121 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12126 cv = function(v){ return v === true || v === "true" || v == 1; };
12133 if(v instanceof Date){
12137 if(dateFormat == "timestamp"){
12138 return new Date(v*1000);
12140 return Date.parseDate(v, dateFormat);
12142 var parsed = Date.parse(v);
12143 return parsed ? new Date(parsed) : null;
12152 Roo.data.Field.prototype = {
12160 * Ext JS Library 1.1.1
12161 * Copyright(c) 2006-2007, Ext JS, LLC.
12163 * Originally Released Under LGPL - original licence link has changed is not relivant.
12166 * <script type="text/javascript">
12169 // Base class for reading structured data from a data source. This class is intended to be
12170 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12173 * @class Roo.data.DataReader
12174 * Base class for reading structured data from a data source. This class is intended to be
12175 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12178 Roo.data.DataReader = function(meta, recordType){
12182 this.recordType = recordType instanceof Array ?
12183 Roo.data.Record.create(recordType) : recordType;
12186 Roo.data.DataReader.prototype = {
12188 * Create an empty record
12189 * @param {Object} data (optional) - overlay some values
12190 * @return {Roo.data.Record} record created.
12192 newRow : function(d) {
12194 this.recordType.prototype.fields.each(function(c) {
12196 case 'int' : da[c.name] = 0; break;
12197 case 'date' : da[c.name] = new Date(); break;
12198 case 'float' : da[c.name] = 0.0; break;
12199 case 'boolean' : da[c.name] = false; break;
12200 default : da[c.name] = ""; break;
12204 return new this.recordType(Roo.apply(da, d));
12209 * Ext JS Library 1.1.1
12210 * Copyright(c) 2006-2007, Ext JS, LLC.
12212 * Originally Released Under LGPL - original licence link has changed is not relivant.
12215 * <script type="text/javascript">
12219 * @class Roo.data.DataProxy
12220 * @extends Roo.data.Observable
12221 * This class is an abstract base class for implementations which provide retrieval of
12222 * unformatted data objects.<br>
12224 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12225 * (of the appropriate type which knows how to parse the data object) to provide a block of
12226 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12228 * Custom implementations must implement the load method as described in
12229 * {@link Roo.data.HttpProxy#load}.
12231 Roo.data.DataProxy = function(){
12234 * @event beforeload
12235 * Fires before a network request is made to retrieve a data object.
12236 * @param {Object} This DataProxy object.
12237 * @param {Object} params The params parameter to the load function.
12242 * Fires before the load method's callback is called.
12243 * @param {Object} This DataProxy object.
12244 * @param {Object} o The data object.
12245 * @param {Object} arg The callback argument object passed to the load function.
12249 * @event loadexception
12250 * Fires if an Exception occurs during data retrieval.
12251 * @param {Object} This DataProxy object.
12252 * @param {Object} o The data object.
12253 * @param {Object} arg The callback argument object passed to the load function.
12254 * @param {Object} e The Exception.
12256 loadexception : true
12258 Roo.data.DataProxy.superclass.constructor.call(this);
12261 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12264 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12268 * Ext JS Library 1.1.1
12269 * Copyright(c) 2006-2007, Ext JS, LLC.
12271 * Originally Released Under LGPL - original licence link has changed is not relivant.
12274 * <script type="text/javascript">
12277 * @class Roo.data.MemoryProxy
12278 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12279 * to the Reader when its load method is called.
12281 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12283 Roo.data.MemoryProxy = function(data){
12287 Roo.data.MemoryProxy.superclass.constructor.call(this);
12291 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12294 * Load data from the requested source (in this case an in-memory
12295 * data object passed to the constructor), read the data object into
12296 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12297 * process that block using the passed callback.
12298 * @param {Object} params This parameter is not used by the MemoryProxy class.
12299 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12300 * object into a block of Roo.data.Records.
12301 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12302 * The function must be passed <ul>
12303 * <li>The Record block object</li>
12304 * <li>The "arg" argument from the load function</li>
12305 * <li>A boolean success indicator</li>
12307 * @param {Object} scope The scope in which to call the callback
12308 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12310 load : function(params, reader, callback, scope, arg){
12311 params = params || {};
12314 result = reader.readRecords(this.data);
12316 this.fireEvent("loadexception", this, arg, null, e);
12317 callback.call(scope, null, arg, false);
12320 callback.call(scope, result, arg, true);
12324 update : function(params, records){
12329 * Ext JS Library 1.1.1
12330 * Copyright(c) 2006-2007, Ext JS, LLC.
12332 * Originally Released Under LGPL - original licence link has changed is not relivant.
12335 * <script type="text/javascript">
12338 * @class Roo.data.HttpProxy
12339 * @extends Roo.data.DataProxy
12340 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12341 * configured to reference a certain URL.<br><br>
12343 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12344 * from which the running page was served.<br><br>
12346 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12348 * Be aware that to enable the browser to parse an XML document, the server must set
12349 * the Content-Type header in the HTTP response to "text/xml".
12351 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12352 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12353 * will be used to make the request.
12355 Roo.data.HttpProxy = function(conn){
12356 Roo.data.HttpProxy.superclass.constructor.call(this);
12357 // is conn a conn config or a real conn?
12359 this.useAjax = !conn || !conn.events;
12363 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12364 // thse are take from connection...
12367 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12370 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12371 * extra parameters to each request made by this object. (defaults to undefined)
12374 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12375 * to each request made by this object. (defaults to undefined)
12378 * @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)
12381 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12384 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12390 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12394 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12395 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12396 * a finer-grained basis than the DataProxy events.
12398 getConnection : function(){
12399 return this.useAjax ? Roo.Ajax : this.conn;
12403 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12404 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12405 * process that block using the passed callback.
12406 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12407 * for the request to the remote server.
12408 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12409 * object into a block of Roo.data.Records.
12410 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12411 * The function must be passed <ul>
12412 * <li>The Record block object</li>
12413 * <li>The "arg" argument from the load function</li>
12414 * <li>A boolean success indicator</li>
12416 * @param {Object} scope The scope in which to call the callback
12417 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12419 load : function(params, reader, callback, scope, arg){
12420 if(this.fireEvent("beforeload", this, params) !== false){
12422 params : params || {},
12424 callback : callback,
12429 callback : this.loadResponse,
12433 Roo.applyIf(o, this.conn);
12434 if(this.activeRequest){
12435 Roo.Ajax.abort(this.activeRequest);
12437 this.activeRequest = Roo.Ajax.request(o);
12439 this.conn.request(o);
12442 callback.call(scope||this, null, arg, false);
12447 loadResponse : function(o, success, response){
12448 delete this.activeRequest;
12450 this.fireEvent("loadexception", this, o, response);
12451 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12456 result = o.reader.read(response);
12458 this.fireEvent("loadexception", this, o, response, e);
12459 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12463 this.fireEvent("load", this, o, o.request.arg);
12464 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12468 update : function(dataSet){
12473 updateResponse : function(dataSet){
12478 * Ext JS Library 1.1.1
12479 * Copyright(c) 2006-2007, Ext JS, LLC.
12481 * Originally Released Under LGPL - original licence link has changed is not relivant.
12484 * <script type="text/javascript">
12488 * @class Roo.data.ScriptTagProxy
12489 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12490 * other than the originating domain of the running page.<br><br>
12492 * <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
12493 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12495 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12496 * source code that is used as the source inside a <script> tag.<br><br>
12498 * In order for the browser to process the returned data, the server must wrap the data object
12499 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12500 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12501 * depending on whether the callback name was passed:
12504 boolean scriptTag = false;
12505 String cb = request.getParameter("callback");
12508 response.setContentType("text/javascript");
12510 response.setContentType("application/x-json");
12512 Writer out = response.getWriter();
12514 out.write(cb + "(");
12516 out.print(dataBlock.toJsonString());
12523 * @param {Object} config A configuration object.
12525 Roo.data.ScriptTagProxy = function(config){
12526 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12527 Roo.apply(this, config);
12528 this.head = document.getElementsByTagName("head")[0];
12531 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12533 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12535 * @cfg {String} url The URL from which to request the data object.
12538 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12542 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12543 * the server the name of the callback function set up by the load call to process the returned data object.
12544 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12545 * javascript output which calls this named function passing the data object as its only parameter.
12547 callbackParam : "callback",
12549 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12550 * name to the request.
12555 * Load data from the configured URL, read the data object into
12556 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12557 * process that block using the passed callback.
12558 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12559 * for the request to the remote server.
12560 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12561 * object into a block of Roo.data.Records.
12562 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12563 * The function must be passed <ul>
12564 * <li>The Record block object</li>
12565 * <li>The "arg" argument from the load function</li>
12566 * <li>A boolean success indicator</li>
12568 * @param {Object} scope The scope in which to call the callback
12569 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12571 load : function(params, reader, callback, scope, arg){
12572 if(this.fireEvent("beforeload", this, params) !== false){
12574 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12576 var url = this.url;
12577 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12579 url += "&_dc=" + (new Date().getTime());
12581 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12584 cb : "stcCallback"+transId,
12585 scriptId : "stcScript"+transId,
12589 callback : callback,
12595 window[trans.cb] = function(o){
12596 conn.handleResponse(o, trans);
12599 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12601 if(this.autoAbort !== false){
12605 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12607 var script = document.createElement("script");
12608 script.setAttribute("src", url);
12609 script.setAttribute("type", "text/javascript");
12610 script.setAttribute("id", trans.scriptId);
12611 this.head.appendChild(script);
12613 this.trans = trans;
12615 callback.call(scope||this, null, arg, false);
12620 isLoading : function(){
12621 return this.trans ? true : false;
12625 * Abort the current server request.
12627 abort : function(){
12628 if(this.isLoading()){
12629 this.destroyTrans(this.trans);
12634 destroyTrans : function(trans, isLoaded){
12635 this.head.removeChild(document.getElementById(trans.scriptId));
12636 clearTimeout(trans.timeoutId);
12638 window[trans.cb] = undefined;
12640 delete window[trans.cb];
12643 // if hasn't been loaded, wait for load to remove it to prevent script error
12644 window[trans.cb] = function(){
12645 window[trans.cb] = undefined;
12647 delete window[trans.cb];
12654 handleResponse : function(o, trans){
12655 this.trans = false;
12656 this.destroyTrans(trans, true);
12659 result = trans.reader.readRecords(o);
12661 this.fireEvent("loadexception", this, o, trans.arg, e);
12662 trans.callback.call(trans.scope||window, null, trans.arg, false);
12665 this.fireEvent("load", this, o, trans.arg);
12666 trans.callback.call(trans.scope||window, result, trans.arg, true);
12670 handleFailure : function(trans){
12671 this.trans = false;
12672 this.destroyTrans(trans, false);
12673 this.fireEvent("loadexception", this, null, trans.arg);
12674 trans.callback.call(trans.scope||window, null, trans.arg, false);
12678 * Ext JS Library 1.1.1
12679 * Copyright(c) 2006-2007, Ext JS, LLC.
12681 * Originally Released Under LGPL - original licence link has changed is not relivant.
12684 * <script type="text/javascript">
12688 * @class Roo.data.JsonReader
12689 * @extends Roo.data.DataReader
12690 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12691 * based on mappings in a provided Roo.data.Record constructor.
12693 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12694 * in the reply previously.
12699 var RecordDef = Roo.data.Record.create([
12700 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12701 {name: 'occupation'} // This field will use "occupation" as the mapping.
12703 var myReader = new Roo.data.JsonReader({
12704 totalProperty: "results", // The property which contains the total dataset size (optional)
12705 root: "rows", // The property which contains an Array of row objects
12706 id: "id" // The property within each row object that provides an ID for the record (optional)
12710 * This would consume a JSON file like this:
12712 { 'results': 2, 'rows': [
12713 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12714 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12717 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12718 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12719 * paged from the remote server.
12720 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12721 * @cfg {String} root name of the property which contains the Array of row objects.
12722 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12723 * @cfg {Array} fields Array of field definition objects
12725 * Create a new JsonReader
12726 * @param {Object} meta Metadata configuration options
12727 * @param {Object} recordType Either an Array of field definition objects,
12728 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12730 Roo.data.JsonReader = function(meta, recordType){
12733 // set some defaults:
12734 Roo.applyIf(meta, {
12735 totalProperty: 'total',
12736 successProperty : 'success',
12741 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12743 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12746 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12747 * Used by Store query builder to append _requestMeta to params.
12750 metaFromRemote : false,
12752 * This method is only used by a DataProxy which has retrieved data from a remote server.
12753 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12754 * @return {Object} data A data block which is used by an Roo.data.Store object as
12755 * a cache of Roo.data.Records.
12757 read : function(response){
12758 var json = response.responseText;
12760 var o = /* eval:var:o */ eval("("+json+")");
12762 throw {message: "JsonReader.read: Json object not found"};
12768 this.metaFromRemote = true;
12769 this.meta = o.metaData;
12770 this.recordType = Roo.data.Record.create(o.metaData.fields);
12771 this.onMetaChange(this.meta, this.recordType, o);
12773 return this.readRecords(o);
12776 // private function a store will implement
12777 onMetaChange : function(meta, recordType, o){
12784 simpleAccess: function(obj, subsc) {
12791 getJsonAccessor: function(){
12793 return function(expr) {
12795 return(re.test(expr))
12796 ? new Function("obj", "return obj." + expr)
12801 return Roo.emptyFn;
12806 * Create a data block containing Roo.data.Records from an XML document.
12807 * @param {Object} o An object which contains an Array of row objects in the property specified
12808 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12809 * which contains the total size of the dataset.
12810 * @return {Object} data A data block which is used by an Roo.data.Store object as
12811 * a cache of Roo.data.Records.
12813 readRecords : function(o){
12815 * After any data loads, the raw JSON data is available for further custom processing.
12819 var s = this.meta, Record = this.recordType,
12820 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12822 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12824 if(s.totalProperty) {
12825 this.getTotal = this.getJsonAccessor(s.totalProperty);
12827 if(s.successProperty) {
12828 this.getSuccess = this.getJsonAccessor(s.successProperty);
12830 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12832 var g = this.getJsonAccessor(s.id);
12833 this.getId = function(rec) {
12835 return (r === undefined || r === "") ? null : r;
12838 this.getId = function(){return null;};
12841 for(var jj = 0; jj < fl; jj++){
12843 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12844 this.ef[jj] = this.getJsonAccessor(map);
12848 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12849 if(s.totalProperty){
12850 var vt = parseInt(this.getTotal(o), 10);
12855 if(s.successProperty){
12856 var vs = this.getSuccess(o);
12857 if(vs === false || vs === 'false'){
12862 for(var i = 0; i < c; i++){
12865 var id = this.getId(n);
12866 for(var j = 0; j < fl; j++){
12868 var v = this.ef[j](n);
12870 Roo.log('missing convert for ' + f.name);
12874 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12876 var record = new Record(values, id);
12878 records[i] = record;
12884 totalRecords : totalRecords
12889 * Ext JS Library 1.1.1
12890 * Copyright(c) 2006-2007, Ext JS, LLC.
12892 * Originally Released Under LGPL - original licence link has changed is not relivant.
12895 * <script type="text/javascript">
12899 * @class Roo.data.ArrayReader
12900 * @extends Roo.data.DataReader
12901 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12902 * Each element of that Array represents a row of data fields. The
12903 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12904 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12908 var RecordDef = Roo.data.Record.create([
12909 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12910 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12912 var myReader = new Roo.data.ArrayReader({
12913 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12917 * This would consume an Array like this:
12919 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12921 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12923 * Create a new JsonReader
12924 * @param {Object} meta Metadata configuration options.
12925 * @param {Object} recordType Either an Array of field definition objects
12926 * as specified to {@link Roo.data.Record#create},
12927 * or an {@link Roo.data.Record} object
12928 * created using {@link Roo.data.Record#create}.
12930 Roo.data.ArrayReader = function(meta, recordType){
12931 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12934 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12936 * Create a data block containing Roo.data.Records from an XML document.
12937 * @param {Object} o An Array of row objects which represents the dataset.
12938 * @return {Object} data A data block which is used by an Roo.data.Store object as
12939 * a cache of Roo.data.Records.
12941 readRecords : function(o){
12942 var sid = this.meta ? this.meta.id : null;
12943 var recordType = this.recordType, fields = recordType.prototype.fields;
12946 for(var i = 0; i < root.length; i++){
12949 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12950 for(var j = 0, jlen = fields.length; j < jlen; j++){
12951 var f = fields.items[j];
12952 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12953 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12955 values[f.name] = v;
12957 var record = new recordType(values, id);
12959 records[records.length] = record;
12963 totalRecords : records.length
12972 * @class Roo.bootstrap.ComboBox
12973 * @extends Roo.bootstrap.TriggerField
12974 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12975 * @cfg {Boolean} append (true|false) default false
12976 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12977 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12978 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12979 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12980 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12981 * @cfg {Boolean} animate default true
12982 * @cfg {Boolean} emptyResultText only for touch device
12983 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12984 * @cfg {String} emptyTitle default ''
12986 * Create a new ComboBox.
12987 * @param {Object} config Configuration options
12989 Roo.bootstrap.ComboBox = function(config){
12990 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12994 * Fires when the dropdown list is expanded
12995 * @param {Roo.bootstrap.ComboBox} combo This combo box
13000 * Fires when the dropdown list is collapsed
13001 * @param {Roo.bootstrap.ComboBox} combo This combo box
13005 * @event beforeselect
13006 * Fires before a list item is selected. Return false to cancel the selection.
13007 * @param {Roo.bootstrap.ComboBox} combo This combo box
13008 * @param {Roo.data.Record} record The data record returned from the underlying store
13009 * @param {Number} index The index of the selected item in the dropdown list
13011 'beforeselect' : true,
13014 * Fires when a list item is selected
13015 * @param {Roo.bootstrap.ComboBox} combo This combo box
13016 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13017 * @param {Number} index The index of the selected item in the dropdown list
13021 * @event beforequery
13022 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13023 * The event object passed has these properties:
13024 * @param {Roo.bootstrap.ComboBox} combo This combo box
13025 * @param {String} query The query
13026 * @param {Boolean} forceAll true to force "all" query
13027 * @param {Boolean} cancel true to cancel the query
13028 * @param {Object} e The query event object
13030 'beforequery': true,
13033 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13034 * @param {Roo.bootstrap.ComboBox} combo This combo box
13039 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13040 * @param {Roo.bootstrap.ComboBox} combo This combo box
13041 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13046 * Fires when the remove value from the combobox array
13047 * @param {Roo.bootstrap.ComboBox} combo This combo box
13051 * @event afterremove
13052 * Fires when the remove value from the combobox array
13053 * @param {Roo.bootstrap.ComboBox} combo This combo box
13055 'afterremove' : true,
13057 * @event specialfilter
13058 * Fires when specialfilter
13059 * @param {Roo.bootstrap.ComboBox} combo This combo box
13061 'specialfilter' : true,
13064 * Fires when tick the element
13065 * @param {Roo.bootstrap.ComboBox} combo This combo box
13069 * @event touchviewdisplay
13070 * Fires when touch view require special display (default is using displayField)
13071 * @param {Roo.bootstrap.ComboBox} combo This combo box
13072 * @param {Object} cfg set html .
13074 'touchviewdisplay' : true
13079 this.tickItems = [];
13081 this.selectedIndex = -1;
13082 if(this.mode == 'local'){
13083 if(config.queryDelay === undefined){
13084 this.queryDelay = 10;
13086 if(config.minChars === undefined){
13092 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13095 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13096 * rendering into an Roo.Editor, defaults to false)
13099 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13100 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13103 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13106 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13107 * the dropdown list (defaults to undefined, with no header element)
13111 * @cfg {String/Roo.Template} tpl The template to use to render the output
13115 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13117 listWidth: undefined,
13119 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13120 * mode = 'remote' or 'text' if mode = 'local')
13122 displayField: undefined,
13125 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13126 * mode = 'remote' or 'value' if mode = 'local').
13127 * Note: use of a valueField requires the user make a selection
13128 * in order for a value to be mapped.
13130 valueField: undefined,
13132 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13137 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13138 * field's data value (defaults to the underlying DOM element's name)
13140 hiddenName: undefined,
13142 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13146 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13148 selectedClass: 'active',
13151 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13155 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13156 * anchor positions (defaults to 'tl-bl')
13158 listAlign: 'tl-bl?',
13160 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13164 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13165 * query specified by the allQuery config option (defaults to 'query')
13167 triggerAction: 'query',
13169 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13170 * (defaults to 4, does not apply if editable = false)
13174 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13175 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13179 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13180 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13184 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13185 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13189 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13190 * when editable = true (defaults to false)
13192 selectOnFocus:false,
13194 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13196 queryParam: 'query',
13198 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13199 * when mode = 'remote' (defaults to 'Loading...')
13201 loadingText: 'Loading...',
13203 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13207 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13211 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13212 * traditional select (defaults to true)
13216 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13220 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13224 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13225 * listWidth has a higher value)
13229 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13230 * allow the user to set arbitrary text into the field (defaults to false)
13232 forceSelection:false,
13234 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13235 * if typeAhead = true (defaults to 250)
13237 typeAheadDelay : 250,
13239 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13240 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13242 valueNotFoundText : undefined,
13244 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13246 blockFocus : false,
13249 * @cfg {Boolean} disableClear Disable showing of clear button.
13251 disableClear : false,
13253 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13255 alwaysQuery : false,
13258 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13263 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13265 invalidClass : "has-warning",
13268 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13270 validClass : "has-success",
13273 * @cfg {Boolean} specialFilter (true|false) special filter default false
13275 specialFilter : false,
13278 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13280 mobileTouchView : true,
13283 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13285 useNativeIOS : false,
13288 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13290 mobile_restrict_height : false,
13292 ios_options : false,
13304 btnPosition : 'right',
13305 triggerList : true,
13306 showToggleBtn : true,
13308 emptyResultText: 'Empty',
13309 triggerText : 'Select',
13312 // element that contains real text value.. (when hidden is used..)
13314 getAutoCreate : function()
13319 * Render classic select for iso
13322 if(Roo.isIOS && this.useNativeIOS){
13323 cfg = this.getAutoCreateNativeIOS();
13331 if(Roo.isTouch && this.mobileTouchView){
13332 cfg = this.getAutoCreateTouchView();
13339 if(!this.tickable){
13340 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13345 * ComboBox with tickable selections
13348 var align = this.labelAlign || this.parentLabelAlign();
13351 cls : 'form-group roo-combobox-tickable' //input-group
13354 var btn_text_select = '';
13355 var btn_text_done = '';
13356 var btn_text_cancel = '';
13358 if (this.btn_text_show) {
13359 btn_text_select = 'Select';
13360 btn_text_done = 'Done';
13361 btn_text_cancel = 'Cancel';
13366 cls : 'tickable-buttons',
13371 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13372 //html : this.triggerText
13373 html: btn_text_select
13379 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13381 html: btn_text_done
13387 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13389 html: btn_text_cancel
13395 buttons.cn.unshift({
13397 cls: 'roo-select2-search-field-input'
13403 Roo.each(buttons.cn, function(c){
13405 c.cls += ' btn-' + _this.size;
13408 if (_this.disabled) {
13415 style : 'display: contents',
13420 cls: 'form-hidden-field'
13424 cls: 'roo-select2-choices',
13428 cls: 'roo-select2-search-field',
13439 cls: 'roo-select2-container input-group roo-select2-container-multi',
13445 // cls: 'typeahead typeahead-long dropdown-menu',
13446 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13451 if(this.hasFeedback && !this.allowBlank){
13455 cls: 'glyphicon form-control-feedback'
13458 combobox.cn.push(feedback);
13463 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13464 tooltip : 'This field is required'
13466 if (Roo.bootstrap.version == 4) {
13469 style : 'display:none'
13472 if (align ==='left' && this.fieldLabel.length) {
13474 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13481 cls : 'control-label col-form-label',
13482 html : this.fieldLabel
13494 var labelCfg = cfg.cn[1];
13495 var contentCfg = cfg.cn[2];
13498 if(this.indicatorpos == 'right'){
13504 cls : 'control-label col-form-label',
13508 html : this.fieldLabel
13524 labelCfg = cfg.cn[0];
13525 contentCfg = cfg.cn[1];
13529 if(this.labelWidth > 12){
13530 labelCfg.style = "width: " + this.labelWidth + 'px';
13533 if(this.labelWidth < 13 && this.labelmd == 0){
13534 this.labelmd = this.labelWidth;
13537 if(this.labellg > 0){
13538 labelCfg.cls += ' col-lg-' + this.labellg;
13539 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13542 if(this.labelmd > 0){
13543 labelCfg.cls += ' col-md-' + this.labelmd;
13544 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13547 if(this.labelsm > 0){
13548 labelCfg.cls += ' col-sm-' + this.labelsm;
13549 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13552 if(this.labelxs > 0){
13553 labelCfg.cls += ' col-xs-' + this.labelxs;
13554 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13558 } else if ( this.fieldLabel.length) {
13559 // Roo.log(" label");
13564 //cls : 'input-group-addon',
13565 html : this.fieldLabel
13570 if(this.indicatorpos == 'right'){
13574 //cls : 'input-group-addon',
13575 html : this.fieldLabel
13585 // Roo.log(" no label && no align");
13592 ['xs','sm','md','lg'].map(function(size){
13593 if (settings[size]) {
13594 cfg.cls += ' col-' + size + '-' + settings[size];
13602 _initEventsCalled : false,
13605 initEvents: function()
13607 if (this._initEventsCalled) { // as we call render... prevent looping...
13610 this._initEventsCalled = true;
13613 throw "can not find store for combo";
13616 this.indicator = this.indicatorEl();
13618 this.store = Roo.factory(this.store, Roo.data);
13619 this.store.parent = this;
13621 // if we are building from html. then this element is so complex, that we can not really
13622 // use the rendered HTML.
13623 // so we have to trash and replace the previous code.
13624 if (Roo.XComponent.build_from_html) {
13625 // remove this element....
13626 var e = this.el.dom, k=0;
13627 while (e ) { e = e.previousSibling; ++k;}
13632 this.rendered = false;
13634 this.render(this.parent().getChildContainer(true), k);
13637 if(Roo.isIOS && this.useNativeIOS){
13638 this.initIOSView();
13646 if(Roo.isTouch && this.mobileTouchView){
13647 this.initTouchView();
13652 this.initTickableEvents();
13656 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13658 if(this.hiddenName){
13660 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13662 this.hiddenField.dom.value =
13663 this.hiddenValue !== undefined ? this.hiddenValue :
13664 this.value !== undefined ? this.value : '';
13666 // prevent input submission
13667 this.el.dom.removeAttribute('name');
13668 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13673 // this.el.dom.setAttribute('autocomplete', 'off');
13676 var cls = 'x-combo-list';
13678 //this.list = new Roo.Layer({
13679 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13685 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13686 _this.list.setWidth(lw);
13689 this.list.on('mouseover', this.onViewOver, this);
13690 this.list.on('mousemove', this.onViewMove, this);
13691 this.list.on('scroll', this.onViewScroll, this);
13694 this.list.swallowEvent('mousewheel');
13695 this.assetHeight = 0;
13698 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13699 this.assetHeight += this.header.getHeight();
13702 this.innerList = this.list.createChild({cls:cls+'-inner'});
13703 this.innerList.on('mouseover', this.onViewOver, this);
13704 this.innerList.on('mousemove', this.onViewMove, this);
13705 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13707 if(this.allowBlank && !this.pageSize && !this.disableClear){
13708 this.footer = this.list.createChild({cls:cls+'-ft'});
13709 this.pageTb = new Roo.Toolbar(this.footer);
13713 this.footer = this.list.createChild({cls:cls+'-ft'});
13714 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13715 {pageSize: this.pageSize});
13719 if (this.pageTb && this.allowBlank && !this.disableClear) {
13721 this.pageTb.add(new Roo.Toolbar.Fill(), {
13722 cls: 'x-btn-icon x-btn-clear',
13724 handler: function()
13727 _this.clearValue();
13728 _this.onSelect(false, -1);
13733 this.assetHeight += this.footer.getHeight();
13738 this.tpl = Roo.bootstrap.version == 4 ?
13739 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13740 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13743 this.view = new Roo.View(this.list, this.tpl, {
13744 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13746 //this.view.wrapEl.setDisplayed(false);
13747 this.view.on('click', this.onViewClick, this);
13750 this.store.on('beforeload', this.onBeforeLoad, this);
13751 this.store.on('load', this.onLoad, this);
13752 this.store.on('loadexception', this.onLoadException, this);
13754 if(this.resizable){
13755 this.resizer = new Roo.Resizable(this.list, {
13756 pinned:true, handles:'se'
13758 this.resizer.on('resize', function(r, w, h){
13759 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13760 this.listWidth = w;
13761 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13762 this.restrictHeight();
13764 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13767 if(!this.editable){
13768 this.editable = true;
13769 this.setEditable(false);
13774 if (typeof(this.events.add.listeners) != 'undefined') {
13776 this.addicon = this.wrap.createChild(
13777 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13779 this.addicon.on('click', function(e) {
13780 this.fireEvent('add', this);
13783 if (typeof(this.events.edit.listeners) != 'undefined') {
13785 this.editicon = this.wrap.createChild(
13786 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13787 if (this.addicon) {
13788 this.editicon.setStyle('margin-left', '40px');
13790 this.editicon.on('click', function(e) {
13792 // we fire even if inothing is selected..
13793 this.fireEvent('edit', this, this.lastData );
13799 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13800 "up" : function(e){
13801 this.inKeyMode = true;
13805 "down" : function(e){
13806 if(!this.isExpanded()){
13807 this.onTriggerClick();
13809 this.inKeyMode = true;
13814 "enter" : function(e){
13815 // this.onViewClick();
13819 if(this.fireEvent("specialkey", this, e)){
13820 this.onViewClick(false);
13826 "esc" : function(e){
13830 "tab" : function(e){
13833 if(this.fireEvent("specialkey", this, e)){
13834 this.onViewClick(false);
13842 doRelay : function(foo, bar, hname){
13843 if(hname == 'down' || this.scope.isExpanded()){
13844 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13853 this.queryDelay = Math.max(this.queryDelay || 10,
13854 this.mode == 'local' ? 10 : 250);
13857 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13859 if(this.typeAhead){
13860 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13862 if(this.editable !== false){
13863 this.inputEl().on("keyup", this.onKeyUp, this);
13865 if(this.forceSelection){
13866 this.inputEl().on('blur', this.doForce, this);
13870 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13871 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13875 initTickableEvents: function()
13879 if(this.hiddenName){
13881 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13883 this.hiddenField.dom.value =
13884 this.hiddenValue !== undefined ? this.hiddenValue :
13885 this.value !== undefined ? this.value : '';
13887 // prevent input submission
13888 this.el.dom.removeAttribute('name');
13889 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13894 // this.list = this.el.select('ul.dropdown-menu',true).first();
13896 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13897 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13898 if(this.triggerList){
13899 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13902 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13903 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13905 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13906 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13908 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13909 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13911 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13912 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13913 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13916 this.cancelBtn.hide();
13921 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13922 _this.list.setWidth(lw);
13925 this.list.on('mouseover', this.onViewOver, this);
13926 this.list.on('mousemove', this.onViewMove, this);
13928 this.list.on('scroll', this.onViewScroll, this);
13931 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13932 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13935 this.view = new Roo.View(this.list, this.tpl, {
13940 selectedClass: this.selectedClass
13943 //this.view.wrapEl.setDisplayed(false);
13944 this.view.on('click', this.onViewClick, this);
13948 this.store.on('beforeload', this.onBeforeLoad, this);
13949 this.store.on('load', this.onLoad, this);
13950 this.store.on('loadexception', this.onLoadException, this);
13953 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13954 "up" : function(e){
13955 this.inKeyMode = true;
13959 "down" : function(e){
13960 this.inKeyMode = true;
13964 "enter" : function(e){
13965 if(this.fireEvent("specialkey", this, e)){
13966 this.onViewClick(false);
13972 "esc" : function(e){
13973 this.onTickableFooterButtonClick(e, false, false);
13976 "tab" : function(e){
13977 this.fireEvent("specialkey", this, e);
13979 this.onTickableFooterButtonClick(e, false, false);
13986 doRelay : function(e, fn, key){
13987 if(this.scope.isExpanded()){
13988 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13997 this.queryDelay = Math.max(this.queryDelay || 10,
13998 this.mode == 'local' ? 10 : 250);
14001 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14003 if(this.typeAhead){
14004 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14007 if(this.editable !== false){
14008 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14011 this.indicator = this.indicatorEl();
14013 if(this.indicator){
14014 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14015 this.indicator.hide();
14020 onDestroy : function(){
14022 this.view.setStore(null);
14023 this.view.el.removeAllListeners();
14024 this.view.el.remove();
14025 this.view.purgeListeners();
14028 this.list.dom.innerHTML = '';
14032 this.store.un('beforeload', this.onBeforeLoad, this);
14033 this.store.un('load', this.onLoad, this);
14034 this.store.un('loadexception', this.onLoadException, this);
14036 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14040 fireKey : function(e){
14041 if(e.isNavKeyPress() && !this.list.isVisible()){
14042 this.fireEvent("specialkey", this, e);
14047 onResize: function(w, h){
14048 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14050 // if(typeof w != 'number'){
14051 // // we do not handle it!?!?
14054 // var tw = this.trigger.getWidth();
14055 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14056 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14058 // this.inputEl().setWidth( this.adjustWidth('input', x));
14060 // //this.trigger.setStyle('left', x+'px');
14062 // if(this.list && this.listWidth === undefined){
14063 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14064 // this.list.setWidth(lw);
14065 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14073 * Allow or prevent the user from directly editing the field text. If false is passed,
14074 * the user will only be able to select from the items defined in the dropdown list. This method
14075 * is the runtime equivalent of setting the 'editable' config option at config time.
14076 * @param {Boolean} value True to allow the user to directly edit the field text
14078 setEditable : function(value){
14079 if(value == this.editable){
14082 this.editable = value;
14084 this.inputEl().dom.setAttribute('readOnly', true);
14085 this.inputEl().on('mousedown', this.onTriggerClick, this);
14086 this.inputEl().addClass('x-combo-noedit');
14088 this.inputEl().dom.setAttribute('readOnly', false);
14089 this.inputEl().un('mousedown', this.onTriggerClick, this);
14090 this.inputEl().removeClass('x-combo-noedit');
14096 onBeforeLoad : function(combo,opts){
14097 if(!this.hasFocus){
14101 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14103 this.restrictHeight();
14104 this.selectedIndex = -1;
14108 onLoad : function(){
14110 this.hasQuery = false;
14112 if(!this.hasFocus){
14116 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14117 this.loading.hide();
14120 if(this.store.getCount() > 0){
14123 this.restrictHeight();
14124 if(this.lastQuery == this.allQuery){
14125 if(this.editable && !this.tickable){
14126 this.inputEl().dom.select();
14130 !this.selectByValue(this.value, true) &&
14133 !this.store.lastOptions ||
14134 typeof(this.store.lastOptions.add) == 'undefined' ||
14135 this.store.lastOptions.add != true
14138 this.select(0, true);
14141 if(this.autoFocus){
14144 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14145 this.taTask.delay(this.typeAheadDelay);
14149 this.onEmptyResults();
14155 onLoadException : function()
14157 this.hasQuery = false;
14159 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14160 this.loading.hide();
14163 if(this.tickable && this.editable){
14168 // only causes errors at present
14169 //Roo.log(this.store.reader.jsonData);
14170 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14172 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14178 onTypeAhead : function(){
14179 if(this.store.getCount() > 0){
14180 var r = this.store.getAt(0);
14181 var newValue = r.data[this.displayField];
14182 var len = newValue.length;
14183 var selStart = this.getRawValue().length;
14185 if(selStart != len){
14186 this.setRawValue(newValue);
14187 this.selectText(selStart, newValue.length);
14193 onSelect : function(record, index){
14195 if(this.fireEvent('beforeselect', this, record, index) !== false){
14197 this.setFromData(index > -1 ? record.data : false);
14200 this.fireEvent('select', this, record, index);
14205 * Returns the currently selected field value or empty string if no value is set.
14206 * @return {String} value The selected value
14208 getValue : function()
14210 if(Roo.isIOS && this.useNativeIOS){
14211 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14215 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14218 if(this.valueField){
14219 return typeof this.value != 'undefined' ? this.value : '';
14221 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14225 getRawValue : function()
14227 if(Roo.isIOS && this.useNativeIOS){
14228 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14231 var v = this.inputEl().getValue();
14237 * Clears any text/value currently set in the field
14239 clearValue : function(){
14241 if(this.hiddenField){
14242 this.hiddenField.dom.value = '';
14245 this.setRawValue('');
14246 this.lastSelectionText = '';
14247 this.lastData = false;
14249 var close = this.closeTriggerEl();
14260 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14261 * will be displayed in the field. If the value does not match the data value of an existing item,
14262 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14263 * Otherwise the field will be blank (although the value will still be set).
14264 * @param {String} value The value to match
14266 setValue : function(v)
14268 if(Roo.isIOS && this.useNativeIOS){
14269 this.setIOSValue(v);
14279 if(this.valueField){
14280 var r = this.findRecord(this.valueField, v);
14282 text = r.data[this.displayField];
14283 }else if(this.valueNotFoundText !== undefined){
14284 text = this.valueNotFoundText;
14287 this.lastSelectionText = text;
14288 if(this.hiddenField){
14289 this.hiddenField.dom.value = v;
14291 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14294 var close = this.closeTriggerEl();
14297 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14303 * @property {Object} the last set data for the element
14308 * Sets the value of the field based on a object which is related to the record format for the store.
14309 * @param {Object} value the value to set as. or false on reset?
14311 setFromData : function(o){
14318 var dv = ''; // display value
14319 var vv = ''; // value value..
14321 if (this.displayField) {
14322 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14324 // this is an error condition!!!
14325 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14328 if(this.valueField){
14329 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14332 var close = this.closeTriggerEl();
14335 if(dv.length || vv * 1 > 0){
14337 this.blockFocus=true;
14343 if(this.hiddenField){
14344 this.hiddenField.dom.value = vv;
14346 this.lastSelectionText = dv;
14347 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14351 // no hidden field.. - we store the value in 'value', but still display
14352 // display field!!!!
14353 this.lastSelectionText = dv;
14354 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14361 reset : function(){
14362 // overridden so that last data is reset..
14369 this.setValue(this.originalValue);
14370 //this.clearInvalid();
14371 this.lastData = false;
14373 this.view.clearSelections();
14379 findRecord : function(prop, value){
14381 if(this.store.getCount() > 0){
14382 this.store.each(function(r){
14383 if(r.data[prop] == value){
14393 getName: function()
14395 // returns hidden if it's set..
14396 if (!this.rendered) {return ''};
14397 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14401 onViewMove : function(e, t){
14402 this.inKeyMode = false;
14406 onViewOver : function(e, t){
14407 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14410 var item = this.view.findItemFromChild(t);
14413 var index = this.view.indexOf(item);
14414 this.select(index, false);
14419 onViewClick : function(view, doFocus, el, e)
14421 var index = this.view.getSelectedIndexes()[0];
14423 var r = this.store.getAt(index);
14427 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14434 Roo.each(this.tickItems, function(v,k){
14436 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14438 _this.tickItems.splice(k, 1);
14440 if(typeof(e) == 'undefined' && view == false){
14441 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14453 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14454 this.tickItems.push(r.data);
14457 if(typeof(e) == 'undefined' && view == false){
14458 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14465 this.onSelect(r, index);
14467 if(doFocus !== false && !this.blockFocus){
14468 this.inputEl().focus();
14473 restrictHeight : function(){
14474 //this.innerList.dom.style.height = '';
14475 //var inner = this.innerList.dom;
14476 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14477 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14478 //this.list.beginUpdate();
14479 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14480 this.list.alignTo(this.inputEl(), this.listAlign);
14481 this.list.alignTo(this.inputEl(), this.listAlign);
14482 //this.list.endUpdate();
14486 onEmptyResults : function(){
14488 if(this.tickable && this.editable){
14489 this.hasFocus = false;
14490 this.restrictHeight();
14498 * Returns true if the dropdown list is expanded, else false.
14500 isExpanded : function(){
14501 return this.list.isVisible();
14505 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14506 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14507 * @param {String} value The data value of the item to select
14508 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14509 * selected item if it is not currently in view (defaults to true)
14510 * @return {Boolean} True if the value matched an item in the list, else false
14512 selectByValue : function(v, scrollIntoView){
14513 if(v !== undefined && v !== null){
14514 var r = this.findRecord(this.valueField || this.displayField, v);
14516 this.select(this.store.indexOf(r), scrollIntoView);
14524 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14525 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14526 * @param {Number} index The zero-based index of the list item to select
14527 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14528 * selected item if it is not currently in view (defaults to true)
14530 select : function(index, scrollIntoView){
14531 this.selectedIndex = index;
14532 this.view.select(index);
14533 if(scrollIntoView !== false){
14534 var el = this.view.getNode(index);
14536 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14539 this.list.scrollChildIntoView(el, false);
14545 selectNext : function(){
14546 var ct = this.store.getCount();
14548 if(this.selectedIndex == -1){
14550 }else if(this.selectedIndex < ct-1){
14551 this.select(this.selectedIndex+1);
14557 selectPrev : function(){
14558 var ct = this.store.getCount();
14560 if(this.selectedIndex == -1){
14562 }else if(this.selectedIndex != 0){
14563 this.select(this.selectedIndex-1);
14569 onKeyUp : function(e){
14570 if(this.editable !== false && !e.isSpecialKey()){
14571 this.lastKey = e.getKey();
14572 this.dqTask.delay(this.queryDelay);
14577 validateBlur : function(){
14578 return !this.list || !this.list.isVisible();
14582 initQuery : function(){
14584 var v = this.getRawValue();
14586 if(this.tickable && this.editable){
14587 v = this.tickableInputEl().getValue();
14594 doForce : function(){
14595 if(this.inputEl().dom.value.length > 0){
14596 this.inputEl().dom.value =
14597 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14603 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14604 * query allowing the query action to be canceled if needed.
14605 * @param {String} query The SQL query to execute
14606 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14607 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14608 * saved in the current store (defaults to false)
14610 doQuery : function(q, forceAll){
14612 if(q === undefined || q === null){
14617 forceAll: forceAll,
14621 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14626 forceAll = qe.forceAll;
14627 if(forceAll === true || (q.length >= this.minChars)){
14629 this.hasQuery = true;
14631 if(this.lastQuery != q || this.alwaysQuery){
14632 this.lastQuery = q;
14633 if(this.mode == 'local'){
14634 this.selectedIndex = -1;
14636 this.store.clearFilter();
14639 if(this.specialFilter){
14640 this.fireEvent('specialfilter', this);
14645 this.store.filter(this.displayField, q);
14648 this.store.fireEvent("datachanged", this.store);
14655 this.store.baseParams[this.queryParam] = q;
14657 var options = {params : this.getParams(q)};
14660 options.add = true;
14661 options.params.start = this.page * this.pageSize;
14664 this.store.load(options);
14667 * this code will make the page width larger, at the beginning, the list not align correctly,
14668 * we should expand the list on onLoad
14669 * so command out it
14674 this.selectedIndex = -1;
14679 this.loadNext = false;
14683 getParams : function(q){
14685 //p[this.queryParam] = q;
14689 p.limit = this.pageSize;
14695 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14697 collapse : function(){
14698 if(!this.isExpanded()){
14704 this.hasFocus = false;
14708 this.cancelBtn.hide();
14709 this.trigger.show();
14712 this.tickableInputEl().dom.value = '';
14713 this.tickableInputEl().blur();
14718 Roo.get(document).un('mousedown', this.collapseIf, this);
14719 Roo.get(document).un('mousewheel', this.collapseIf, this);
14720 if (!this.editable) {
14721 Roo.get(document).un('keydown', this.listKeyPress, this);
14723 this.fireEvent('collapse', this);
14729 collapseIf : function(e){
14730 var in_combo = e.within(this.el);
14731 var in_list = e.within(this.list);
14732 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14734 if (in_combo || in_list || is_list) {
14735 //e.stopPropagation();
14740 this.onTickableFooterButtonClick(e, false, false);
14748 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14750 expand : function(){
14752 if(this.isExpanded() || !this.hasFocus){
14756 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14757 this.list.setWidth(lw);
14763 this.restrictHeight();
14767 this.tickItems = Roo.apply([], this.item);
14770 this.cancelBtn.show();
14771 this.trigger.hide();
14774 this.tickableInputEl().focus();
14779 Roo.get(document).on('mousedown', this.collapseIf, this);
14780 Roo.get(document).on('mousewheel', this.collapseIf, this);
14781 if (!this.editable) {
14782 Roo.get(document).on('keydown', this.listKeyPress, this);
14785 this.fireEvent('expand', this);
14789 // Implements the default empty TriggerField.onTriggerClick function
14790 onTriggerClick : function(e)
14792 Roo.log('trigger click');
14794 if(this.disabled || !this.triggerList){
14799 this.loadNext = false;
14801 if(this.isExpanded()){
14803 if (!this.blockFocus) {
14804 this.inputEl().focus();
14808 this.hasFocus = true;
14809 if(this.triggerAction == 'all') {
14810 this.doQuery(this.allQuery, true);
14812 this.doQuery(this.getRawValue());
14814 if (!this.blockFocus) {
14815 this.inputEl().focus();
14820 onTickableTriggerClick : function(e)
14827 this.loadNext = false;
14828 this.hasFocus = true;
14830 if(this.triggerAction == 'all') {
14831 this.doQuery(this.allQuery, true);
14833 this.doQuery(this.getRawValue());
14837 onSearchFieldClick : function(e)
14839 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14840 this.onTickableFooterButtonClick(e, false, false);
14844 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14849 this.loadNext = false;
14850 this.hasFocus = true;
14852 if(this.triggerAction == 'all') {
14853 this.doQuery(this.allQuery, true);
14855 this.doQuery(this.getRawValue());
14859 listKeyPress : function(e)
14861 //Roo.log('listkeypress');
14862 // scroll to first matching element based on key pres..
14863 if (e.isSpecialKey()) {
14866 var k = String.fromCharCode(e.getKey()).toUpperCase();
14869 var csel = this.view.getSelectedNodes();
14870 var cselitem = false;
14872 var ix = this.view.indexOf(csel[0]);
14873 cselitem = this.store.getAt(ix);
14874 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14880 this.store.each(function(v) {
14882 // start at existing selection.
14883 if (cselitem.id == v.id) {
14889 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14890 match = this.store.indexOf(v);
14896 if (match === false) {
14897 return true; // no more action?
14900 this.view.select(match);
14901 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14902 sn.scrollIntoView(sn.dom.parentNode, false);
14905 onViewScroll : function(e, t){
14907 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){
14911 this.hasQuery = true;
14913 this.loading = this.list.select('.loading', true).first();
14915 if(this.loading === null){
14916 this.list.createChild({
14918 cls: 'loading roo-select2-more-results roo-select2-active',
14919 html: 'Loading more results...'
14922 this.loading = this.list.select('.loading', true).first();
14924 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14926 this.loading.hide();
14929 this.loading.show();
14934 this.loadNext = true;
14936 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14941 addItem : function(o)
14943 var dv = ''; // display value
14945 if (this.displayField) {
14946 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14948 // this is an error condition!!!
14949 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14956 var choice = this.choices.createChild({
14958 cls: 'roo-select2-search-choice',
14967 cls: 'roo-select2-search-choice-close fa fa-times',
14972 }, this.searchField);
14974 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14976 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14984 this.inputEl().dom.value = '';
14989 onRemoveItem : function(e, _self, o)
14991 e.preventDefault();
14993 this.lastItem = Roo.apply([], this.item);
14995 var index = this.item.indexOf(o.data) * 1;
14998 Roo.log('not this item?!');
15002 this.item.splice(index, 1);
15007 this.fireEvent('remove', this, e);
15013 syncValue : function()
15015 if(!this.item.length){
15022 Roo.each(this.item, function(i){
15023 if(_this.valueField){
15024 value.push(i[_this.valueField]);
15031 this.value = value.join(',');
15033 if(this.hiddenField){
15034 this.hiddenField.dom.value = this.value;
15037 this.store.fireEvent("datachanged", this.store);
15042 clearItem : function()
15044 if(!this.multiple){
15050 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15058 if(this.tickable && !Roo.isTouch){
15059 this.view.refresh();
15063 inputEl: function ()
15065 if(Roo.isIOS && this.useNativeIOS){
15066 return this.el.select('select.roo-ios-select', true).first();
15069 if(Roo.isTouch && this.mobileTouchView){
15070 return this.el.select('input.form-control',true).first();
15074 return this.searchField;
15077 return this.el.select('input.form-control',true).first();
15080 onTickableFooterButtonClick : function(e, btn, el)
15082 e.preventDefault();
15084 this.lastItem = Roo.apply([], this.item);
15086 if(btn && btn.name == 'cancel'){
15087 this.tickItems = Roo.apply([], this.item);
15096 Roo.each(this.tickItems, function(o){
15104 validate : function()
15106 if(this.getVisibilityEl().hasClass('hidden')){
15110 var v = this.getRawValue();
15113 v = this.getValue();
15116 if(this.disabled || this.allowBlank || v.length){
15121 this.markInvalid();
15125 tickableInputEl : function()
15127 if(!this.tickable || !this.editable){
15128 return this.inputEl();
15131 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15135 getAutoCreateTouchView : function()
15140 cls: 'form-group' //input-group
15146 type : this.inputType,
15147 cls : 'form-control x-combo-noedit',
15148 autocomplete: 'new-password',
15149 placeholder : this.placeholder || '',
15154 input.name = this.name;
15158 input.cls += ' input-' + this.size;
15161 if (this.disabled) {
15162 input.disabled = true;
15173 inputblock.cls += ' input-group';
15175 inputblock.cn.unshift({
15177 cls : 'input-group-addon input-group-prepend input-group-text',
15182 if(this.removable && !this.multiple){
15183 inputblock.cls += ' roo-removable';
15185 inputblock.cn.push({
15188 cls : 'roo-combo-removable-btn close'
15192 if(this.hasFeedback && !this.allowBlank){
15194 inputblock.cls += ' has-feedback';
15196 inputblock.cn.push({
15198 cls: 'glyphicon form-control-feedback'
15205 inputblock.cls += (this.before) ? '' : ' input-group';
15207 inputblock.cn.push({
15209 cls : 'input-group-addon input-group-append input-group-text',
15215 var ibwrap = inputblock;
15220 cls: 'roo-select2-choices',
15224 cls: 'roo-select2-search-field',
15237 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15242 cls: 'form-hidden-field'
15248 if(!this.multiple && this.showToggleBtn){
15255 if (this.caret != false) {
15258 cls: 'fa fa-' + this.caret
15265 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15270 cls: 'combobox-clear',
15284 combobox.cls += ' roo-select2-container-multi';
15287 var align = this.labelAlign || this.parentLabelAlign();
15289 if (align ==='left' && this.fieldLabel.length) {
15294 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15295 tooltip : 'This field is required'
15299 cls : 'control-label col-form-label',
15300 html : this.fieldLabel
15311 var labelCfg = cfg.cn[1];
15312 var contentCfg = cfg.cn[2];
15315 if(this.indicatorpos == 'right'){
15320 cls : 'control-label col-form-label',
15324 html : this.fieldLabel
15328 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15329 tooltip : 'This field is required'
15342 labelCfg = cfg.cn[0];
15343 contentCfg = cfg.cn[1];
15348 if(this.labelWidth > 12){
15349 labelCfg.style = "width: " + this.labelWidth + 'px';
15352 if(this.labelWidth < 13 && this.labelmd == 0){
15353 this.labelmd = this.labelWidth;
15356 if(this.labellg > 0){
15357 labelCfg.cls += ' col-lg-' + this.labellg;
15358 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15361 if(this.labelmd > 0){
15362 labelCfg.cls += ' col-md-' + this.labelmd;
15363 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15366 if(this.labelsm > 0){
15367 labelCfg.cls += ' col-sm-' + this.labelsm;
15368 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15371 if(this.labelxs > 0){
15372 labelCfg.cls += ' col-xs-' + this.labelxs;
15373 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15377 } else if ( this.fieldLabel.length) {
15381 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15382 tooltip : 'This field is required'
15386 cls : 'control-label',
15387 html : this.fieldLabel
15398 if(this.indicatorpos == 'right'){
15402 cls : 'control-label',
15403 html : this.fieldLabel,
15407 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15408 tooltip : 'This field is required'
15425 var settings = this;
15427 ['xs','sm','md','lg'].map(function(size){
15428 if (settings[size]) {
15429 cfg.cls += ' col-' + size + '-' + settings[size];
15436 initTouchView : function()
15438 this.renderTouchView();
15440 this.touchViewEl.on('scroll', function(){
15441 this.el.dom.scrollTop = 0;
15444 this.originalValue = this.getValue();
15446 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15448 this.inputEl().on("click", this.showTouchView, this);
15449 if (this.triggerEl) {
15450 this.triggerEl.on("click", this.showTouchView, this);
15454 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15455 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15457 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15459 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15460 this.store.on('load', this.onTouchViewLoad, this);
15461 this.store.on('loadexception', this.onTouchViewLoadException, this);
15463 if(this.hiddenName){
15465 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15467 this.hiddenField.dom.value =
15468 this.hiddenValue !== undefined ? this.hiddenValue :
15469 this.value !== undefined ? this.value : '';
15471 this.el.dom.removeAttribute('name');
15472 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15476 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15477 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15480 if(this.removable && !this.multiple){
15481 var close = this.closeTriggerEl();
15483 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15484 close.on('click', this.removeBtnClick, this, close);
15488 * fix the bug in Safari iOS8
15490 this.inputEl().on("focus", function(e){
15491 document.activeElement.blur();
15494 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15501 renderTouchView : function()
15503 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15504 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15506 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15507 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15509 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15510 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15511 this.touchViewBodyEl.setStyle('overflow', 'auto');
15513 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15514 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15516 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15517 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15521 showTouchView : function()
15527 this.touchViewHeaderEl.hide();
15529 if(this.modalTitle.length){
15530 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15531 this.touchViewHeaderEl.show();
15534 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15535 this.touchViewEl.show();
15537 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15539 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15540 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15542 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15544 if(this.modalTitle.length){
15545 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15548 this.touchViewBodyEl.setHeight(bodyHeight);
15552 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15554 this.touchViewEl.addClass('in');
15557 if(this._touchViewMask){
15558 Roo.get(document.body).addClass("x-body-masked");
15559 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15560 this._touchViewMask.setStyle('z-index', 10000);
15561 this._touchViewMask.addClass('show');
15564 this.doTouchViewQuery();
15568 hideTouchView : function()
15570 this.touchViewEl.removeClass('in');
15574 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15576 this.touchViewEl.setStyle('display', 'none');
15579 if(this._touchViewMask){
15580 this._touchViewMask.removeClass('show');
15581 Roo.get(document.body).removeClass("x-body-masked");
15585 setTouchViewValue : function()
15592 Roo.each(this.tickItems, function(o){
15597 this.hideTouchView();
15600 doTouchViewQuery : function()
15609 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15613 if(!this.alwaysQuery || this.mode == 'local'){
15614 this.onTouchViewLoad();
15621 onTouchViewBeforeLoad : function(combo,opts)
15627 onTouchViewLoad : function()
15629 if(this.store.getCount() < 1){
15630 this.onTouchViewEmptyResults();
15634 this.clearTouchView();
15636 var rawValue = this.getRawValue();
15638 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15640 this.tickItems = [];
15642 this.store.data.each(function(d, rowIndex){
15643 var row = this.touchViewListGroup.createChild(template);
15645 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15646 row.addClass(d.data.cls);
15649 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15652 html : d.data[this.displayField]
15655 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15656 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15659 row.removeClass('selected');
15660 if(!this.multiple && this.valueField &&
15661 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15664 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15665 row.addClass('selected');
15668 if(this.multiple && this.valueField &&
15669 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15673 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15674 this.tickItems.push(d.data);
15677 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15681 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15683 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15685 if(this.modalTitle.length){
15686 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15689 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15691 if(this.mobile_restrict_height && listHeight < bodyHeight){
15692 this.touchViewBodyEl.setHeight(listHeight);
15697 if(firstChecked && listHeight > bodyHeight){
15698 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15703 onTouchViewLoadException : function()
15705 this.hideTouchView();
15708 onTouchViewEmptyResults : function()
15710 this.clearTouchView();
15712 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15714 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15718 clearTouchView : function()
15720 this.touchViewListGroup.dom.innerHTML = '';
15723 onTouchViewClick : function(e, el, o)
15725 e.preventDefault();
15728 var rowIndex = o.rowIndex;
15730 var r = this.store.getAt(rowIndex);
15732 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15734 if(!this.multiple){
15735 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15736 c.dom.removeAttribute('checked');
15739 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15741 this.setFromData(r.data);
15743 var close = this.closeTriggerEl();
15749 this.hideTouchView();
15751 this.fireEvent('select', this, r, rowIndex);
15756 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15757 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15758 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15762 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15763 this.addItem(r.data);
15764 this.tickItems.push(r.data);
15768 getAutoCreateNativeIOS : function()
15771 cls: 'form-group' //input-group,
15776 cls : 'roo-ios-select'
15780 combobox.name = this.name;
15783 if (this.disabled) {
15784 combobox.disabled = true;
15787 var settings = this;
15789 ['xs','sm','md','lg'].map(function(size){
15790 if (settings[size]) {
15791 cfg.cls += ' col-' + size + '-' + settings[size];
15801 initIOSView : function()
15803 this.store.on('load', this.onIOSViewLoad, this);
15808 onIOSViewLoad : function()
15810 if(this.store.getCount() < 1){
15814 this.clearIOSView();
15816 if(this.allowBlank) {
15818 var default_text = '-- SELECT --';
15820 if(this.placeholder.length){
15821 default_text = this.placeholder;
15824 if(this.emptyTitle.length){
15825 default_text += ' - ' + this.emptyTitle + ' -';
15828 var opt = this.inputEl().createChild({
15831 html : default_text
15835 o[this.valueField] = 0;
15836 o[this.displayField] = default_text;
15838 this.ios_options.push({
15845 this.store.data.each(function(d, rowIndex){
15849 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15850 html = d.data[this.displayField];
15855 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15856 value = d.data[this.valueField];
15865 if(this.value == d.data[this.valueField]){
15866 option['selected'] = true;
15869 var opt = this.inputEl().createChild(option);
15871 this.ios_options.push({
15878 this.inputEl().on('change', function(){
15879 this.fireEvent('select', this);
15884 clearIOSView: function()
15886 this.inputEl().dom.innerHTML = '';
15888 this.ios_options = [];
15891 setIOSValue: function(v)
15895 if(!this.ios_options){
15899 Roo.each(this.ios_options, function(opts){
15901 opts.el.dom.removeAttribute('selected');
15903 if(opts.data[this.valueField] != v){
15907 opts.el.dom.setAttribute('selected', true);
15913 * @cfg {Boolean} grow
15917 * @cfg {Number} growMin
15921 * @cfg {Number} growMax
15930 Roo.apply(Roo.bootstrap.ComboBox, {
15934 cls: 'modal-header',
15956 cls: 'list-group-item',
15960 cls: 'roo-combobox-list-group-item-value'
15964 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15978 listItemCheckbox : {
15980 cls: 'list-group-item',
15984 cls: 'roo-combobox-list-group-item-value'
15988 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16004 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16009 cls: 'modal-footer',
16017 cls: 'col-xs-6 text-left',
16020 cls: 'btn btn-danger roo-touch-view-cancel',
16026 cls: 'col-xs-6 text-right',
16029 cls: 'btn btn-success roo-touch-view-ok',
16040 Roo.apply(Roo.bootstrap.ComboBox, {
16042 touchViewTemplate : {
16044 cls: 'modal fade roo-combobox-touch-view',
16048 cls: 'modal-dialog',
16049 style : 'position:fixed', // we have to fix position....
16053 cls: 'modal-content',
16055 Roo.bootstrap.ComboBox.header,
16056 Roo.bootstrap.ComboBox.body,
16057 Roo.bootstrap.ComboBox.footer
16066 * Ext JS Library 1.1.1
16067 * Copyright(c) 2006-2007, Ext JS, LLC.
16069 * Originally Released Under LGPL - original licence link has changed is not relivant.
16072 * <script type="text/javascript">
16077 * @extends Roo.util.Observable
16078 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16079 * This class also supports single and multi selection modes. <br>
16080 * Create a data model bound view:
16082 var store = new Roo.data.Store(...);
16084 var view = new Roo.View({
16086 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16088 singleSelect: true,
16089 selectedClass: "ydataview-selected",
16093 // listen for node click?
16094 view.on("click", function(vw, index, node, e){
16095 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16099 dataModel.load("foobar.xml");
16101 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16103 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16104 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16106 * Note: old style constructor is still suported (container, template, config)
16109 * Create a new View
16110 * @param {Object} config The config object
16113 Roo.View = function(config, depreciated_tpl, depreciated_config){
16115 this.parent = false;
16117 if (typeof(depreciated_tpl) == 'undefined') {
16118 // new way.. - universal constructor.
16119 Roo.apply(this, config);
16120 this.el = Roo.get(this.el);
16123 this.el = Roo.get(config);
16124 this.tpl = depreciated_tpl;
16125 Roo.apply(this, depreciated_config);
16127 this.wrapEl = this.el.wrap().wrap();
16128 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16131 if(typeof(this.tpl) == "string"){
16132 this.tpl = new Roo.Template(this.tpl);
16134 // support xtype ctors..
16135 this.tpl = new Roo.factory(this.tpl, Roo);
16139 this.tpl.compile();
16144 * @event beforeclick
16145 * Fires before a click is processed. Returns false to cancel the default action.
16146 * @param {Roo.View} this
16147 * @param {Number} index The index of the target node
16148 * @param {HTMLElement} node The target node
16149 * @param {Roo.EventObject} e The raw event object
16151 "beforeclick" : true,
16154 * Fires when a template node is clicked.
16155 * @param {Roo.View} this
16156 * @param {Number} index The index of the target node
16157 * @param {HTMLElement} node The target node
16158 * @param {Roo.EventObject} e The raw event object
16163 * Fires when a template node is double clicked.
16164 * @param {Roo.View} this
16165 * @param {Number} index The index of the target node
16166 * @param {HTMLElement} node The target node
16167 * @param {Roo.EventObject} e The raw event object
16171 * @event contextmenu
16172 * Fires when a template node is right clicked.
16173 * @param {Roo.View} this
16174 * @param {Number} index The index of the target node
16175 * @param {HTMLElement} node The target node
16176 * @param {Roo.EventObject} e The raw event object
16178 "contextmenu" : true,
16180 * @event selectionchange
16181 * Fires when the selected nodes change.
16182 * @param {Roo.View} this
16183 * @param {Array} selections Array of the selected nodes
16185 "selectionchange" : true,
16188 * @event beforeselect
16189 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16190 * @param {Roo.View} this
16191 * @param {HTMLElement} node The node to be selected
16192 * @param {Array} selections Array of currently selected nodes
16194 "beforeselect" : true,
16196 * @event preparedata
16197 * Fires on every row to render, to allow you to change the data.
16198 * @param {Roo.View} this
16199 * @param {Object} data to be rendered (change this)
16201 "preparedata" : true
16209 "click": this.onClick,
16210 "dblclick": this.onDblClick,
16211 "contextmenu": this.onContextMenu,
16215 this.selections = [];
16217 this.cmp = new Roo.CompositeElementLite([]);
16219 this.store = Roo.factory(this.store, Roo.data);
16220 this.setStore(this.store, true);
16223 if ( this.footer && this.footer.xtype) {
16225 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16227 this.footer.dataSource = this.store;
16228 this.footer.container = fctr;
16229 this.footer = Roo.factory(this.footer, Roo);
16230 fctr.insertFirst(this.el);
16232 // this is a bit insane - as the paging toolbar seems to detach the el..
16233 // dom.parentNode.parentNode.parentNode
16234 // they get detached?
16238 Roo.View.superclass.constructor.call(this);
16243 Roo.extend(Roo.View, Roo.util.Observable, {
16246 * @cfg {Roo.data.Store} store Data store to load data from.
16251 * @cfg {String|Roo.Element} el The container element.
16256 * @cfg {String|Roo.Template} tpl The template used by this View
16260 * @cfg {String} dataName the named area of the template to use as the data area
16261 * Works with domtemplates roo-name="name"
16265 * @cfg {String} selectedClass The css class to add to selected nodes
16267 selectedClass : "x-view-selected",
16269 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16274 * @cfg {String} text to display on mask (default Loading)
16278 * @cfg {Boolean} multiSelect Allow multiple selection
16280 multiSelect : false,
16282 * @cfg {Boolean} singleSelect Allow single selection
16284 singleSelect: false,
16287 * @cfg {Boolean} toggleSelect - selecting
16289 toggleSelect : false,
16292 * @cfg {Boolean} tickable - selecting
16297 * Returns the element this view is bound to.
16298 * @return {Roo.Element}
16300 getEl : function(){
16301 return this.wrapEl;
16307 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16309 refresh : function(){
16310 //Roo.log('refresh');
16313 // if we are using something like 'domtemplate', then
16314 // the what gets used is:
16315 // t.applySubtemplate(NAME, data, wrapping data..)
16316 // the outer template then get' applied with
16317 // the store 'extra data'
16318 // and the body get's added to the
16319 // roo-name="data" node?
16320 // <span class='roo-tpl-{name}'></span> ?????
16324 this.clearSelections();
16325 this.el.update("");
16327 var records = this.store.getRange();
16328 if(records.length < 1) {
16330 // is this valid?? = should it render a template??
16332 this.el.update(this.emptyText);
16336 if (this.dataName) {
16337 this.el.update(t.apply(this.store.meta)); //????
16338 el = this.el.child('.roo-tpl-' + this.dataName);
16341 for(var i = 0, len = records.length; i < len; i++){
16342 var data = this.prepareData(records[i].data, i, records[i]);
16343 this.fireEvent("preparedata", this, data, i, records[i]);
16345 var d = Roo.apply({}, data);
16348 Roo.apply(d, {'roo-id' : Roo.id()});
16352 Roo.each(this.parent.item, function(item){
16353 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16356 Roo.apply(d, {'roo-data-checked' : 'checked'});
16360 html[html.length] = Roo.util.Format.trim(
16362 t.applySubtemplate(this.dataName, d, this.store.meta) :
16369 el.update(html.join(""));
16370 this.nodes = el.dom.childNodes;
16371 this.updateIndexes(0);
16376 * Function to override to reformat the data that is sent to
16377 * the template for each node.
16378 * DEPRICATED - use the preparedata event handler.
16379 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16380 * a JSON object for an UpdateManager bound view).
16382 prepareData : function(data, index, record)
16384 this.fireEvent("preparedata", this, data, index, record);
16388 onUpdate : function(ds, record){
16389 // Roo.log('on update');
16390 this.clearSelections();
16391 var index = this.store.indexOf(record);
16392 var n = this.nodes[index];
16393 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16394 n.parentNode.removeChild(n);
16395 this.updateIndexes(index, index);
16401 onAdd : function(ds, records, index)
16403 //Roo.log(['on Add', ds, records, index] );
16404 this.clearSelections();
16405 if(this.nodes.length == 0){
16409 var n = this.nodes[index];
16410 for(var i = 0, len = records.length; i < len; i++){
16411 var d = this.prepareData(records[i].data, i, records[i]);
16413 this.tpl.insertBefore(n, d);
16416 this.tpl.append(this.el, d);
16419 this.updateIndexes(index);
16422 onRemove : function(ds, record, index){
16423 // Roo.log('onRemove');
16424 this.clearSelections();
16425 var el = this.dataName ?
16426 this.el.child('.roo-tpl-' + this.dataName) :
16429 el.dom.removeChild(this.nodes[index]);
16430 this.updateIndexes(index);
16434 * Refresh an individual node.
16435 * @param {Number} index
16437 refreshNode : function(index){
16438 this.onUpdate(this.store, this.store.getAt(index));
16441 updateIndexes : function(startIndex, endIndex){
16442 var ns = this.nodes;
16443 startIndex = startIndex || 0;
16444 endIndex = endIndex || ns.length - 1;
16445 for(var i = startIndex; i <= endIndex; i++){
16446 ns[i].nodeIndex = i;
16451 * Changes the data store this view uses and refresh the view.
16452 * @param {Store} store
16454 setStore : function(store, initial){
16455 if(!initial && this.store){
16456 this.store.un("datachanged", this.refresh);
16457 this.store.un("add", this.onAdd);
16458 this.store.un("remove", this.onRemove);
16459 this.store.un("update", this.onUpdate);
16460 this.store.un("clear", this.refresh);
16461 this.store.un("beforeload", this.onBeforeLoad);
16462 this.store.un("load", this.onLoad);
16463 this.store.un("loadexception", this.onLoad);
16467 store.on("datachanged", this.refresh, this);
16468 store.on("add", this.onAdd, this);
16469 store.on("remove", this.onRemove, this);
16470 store.on("update", this.onUpdate, this);
16471 store.on("clear", this.refresh, this);
16472 store.on("beforeload", this.onBeforeLoad, this);
16473 store.on("load", this.onLoad, this);
16474 store.on("loadexception", this.onLoad, this);
16482 * onbeforeLoad - masks the loading area.
16485 onBeforeLoad : function(store,opts)
16487 //Roo.log('onBeforeLoad');
16489 this.el.update("");
16491 this.el.mask(this.mask ? this.mask : "Loading" );
16493 onLoad : function ()
16500 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16501 * @param {HTMLElement} node
16502 * @return {HTMLElement} The template node
16504 findItemFromChild : function(node){
16505 var el = this.dataName ?
16506 this.el.child('.roo-tpl-' + this.dataName,true) :
16509 if(!node || node.parentNode == el){
16512 var p = node.parentNode;
16513 while(p && p != el){
16514 if(p.parentNode == el){
16523 onClick : function(e){
16524 var item = this.findItemFromChild(e.getTarget());
16526 var index = this.indexOf(item);
16527 if(this.onItemClick(item, index, e) !== false){
16528 this.fireEvent("click", this, index, item, e);
16531 this.clearSelections();
16536 onContextMenu : function(e){
16537 var item = this.findItemFromChild(e.getTarget());
16539 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16544 onDblClick : function(e){
16545 var item = this.findItemFromChild(e.getTarget());
16547 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16551 onItemClick : function(item, index, e)
16553 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16556 if (this.toggleSelect) {
16557 var m = this.isSelected(item) ? 'unselect' : 'select';
16560 _t[m](item, true, false);
16563 if(this.multiSelect || this.singleSelect){
16564 if(this.multiSelect && e.shiftKey && this.lastSelection){
16565 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16567 this.select(item, this.multiSelect && e.ctrlKey);
16568 this.lastSelection = item;
16571 if(!this.tickable){
16572 e.preventDefault();
16580 * Get the number of selected nodes.
16583 getSelectionCount : function(){
16584 return this.selections.length;
16588 * Get the currently selected nodes.
16589 * @return {Array} An array of HTMLElements
16591 getSelectedNodes : function(){
16592 return this.selections;
16596 * Get the indexes of the selected nodes.
16599 getSelectedIndexes : function(){
16600 var indexes = [], s = this.selections;
16601 for(var i = 0, len = s.length; i < len; i++){
16602 indexes.push(s[i].nodeIndex);
16608 * Clear all selections
16609 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16611 clearSelections : function(suppressEvent){
16612 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16613 this.cmp.elements = this.selections;
16614 this.cmp.removeClass(this.selectedClass);
16615 this.selections = [];
16616 if(!suppressEvent){
16617 this.fireEvent("selectionchange", this, this.selections);
16623 * Returns true if the passed node is selected
16624 * @param {HTMLElement/Number} node The node or node index
16625 * @return {Boolean}
16627 isSelected : function(node){
16628 var s = this.selections;
16632 node = this.getNode(node);
16633 return s.indexOf(node) !== -1;
16638 * @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
16639 * @param {Boolean} keepExisting (optional) true to keep existing selections
16640 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16642 select : function(nodeInfo, keepExisting, suppressEvent){
16643 if(nodeInfo instanceof Array){
16645 this.clearSelections(true);
16647 for(var i = 0, len = nodeInfo.length; i < len; i++){
16648 this.select(nodeInfo[i], true, true);
16652 var node = this.getNode(nodeInfo);
16653 if(!node || this.isSelected(node)){
16654 return; // already selected.
16657 this.clearSelections(true);
16660 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16661 Roo.fly(node).addClass(this.selectedClass);
16662 this.selections.push(node);
16663 if(!suppressEvent){
16664 this.fireEvent("selectionchange", this, this.selections);
16672 * @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
16673 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16674 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16676 unselect : function(nodeInfo, keepExisting, suppressEvent)
16678 if(nodeInfo instanceof Array){
16679 Roo.each(this.selections, function(s) {
16680 this.unselect(s, nodeInfo);
16684 var node = this.getNode(nodeInfo);
16685 if(!node || !this.isSelected(node)){
16686 //Roo.log("not selected");
16687 return; // not selected.
16691 Roo.each(this.selections, function(s) {
16693 Roo.fly(node).removeClass(this.selectedClass);
16700 this.selections= ns;
16701 this.fireEvent("selectionchange", this, this.selections);
16705 * Gets a template node.
16706 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16707 * @return {HTMLElement} The node or null if it wasn't found
16709 getNode : function(nodeInfo){
16710 if(typeof nodeInfo == "string"){
16711 return document.getElementById(nodeInfo);
16712 }else if(typeof nodeInfo == "number"){
16713 return this.nodes[nodeInfo];
16719 * Gets a range template nodes.
16720 * @param {Number} startIndex
16721 * @param {Number} endIndex
16722 * @return {Array} An array of nodes
16724 getNodes : function(start, end){
16725 var ns = this.nodes;
16726 start = start || 0;
16727 end = typeof end == "undefined" ? ns.length - 1 : end;
16730 for(var i = start; i <= end; i++){
16734 for(var i = start; i >= end; i--){
16742 * Finds the index of the passed node
16743 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16744 * @return {Number} The index of the node or -1
16746 indexOf : function(node){
16747 node = this.getNode(node);
16748 if(typeof node.nodeIndex == "number"){
16749 return node.nodeIndex;
16751 var ns = this.nodes;
16752 for(var i = 0, len = ns.length; i < len; i++){
16763 * based on jquery fullcalendar
16767 Roo.bootstrap = Roo.bootstrap || {};
16769 * @class Roo.bootstrap.Calendar
16770 * @extends Roo.bootstrap.Component
16771 * Bootstrap Calendar class
16772 * @cfg {Boolean} loadMask (true|false) default false
16773 * @cfg {Object} header generate the user specific header of the calendar, default false
16776 * Create a new Container
16777 * @param {Object} config The config object
16782 Roo.bootstrap.Calendar = function(config){
16783 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16787 * Fires when a date is selected
16788 * @param {DatePicker} this
16789 * @param {Date} date The selected date
16793 * @event monthchange
16794 * Fires when the displayed month changes
16795 * @param {DatePicker} this
16796 * @param {Date} date The selected month
16798 'monthchange': true,
16800 * @event evententer
16801 * Fires when mouse over an event
16802 * @param {Calendar} this
16803 * @param {event} Event
16805 'evententer': true,
16807 * @event eventleave
16808 * Fires when the mouse leaves an
16809 * @param {Calendar} this
16812 'eventleave': true,
16814 * @event eventclick
16815 * Fires when the mouse click an
16816 * @param {Calendar} this
16825 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16828 * @cfg {Number} startDay
16829 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16837 getAutoCreate : function(){
16840 var fc_button = function(name, corner, style, content ) {
16841 return Roo.apply({},{
16843 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16845 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16848 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16859 style : 'width:100%',
16866 cls : 'fc-header-left',
16868 fc_button('prev', 'left', 'arrow', '‹' ),
16869 fc_button('next', 'right', 'arrow', '›' ),
16870 { tag: 'span', cls: 'fc-header-space' },
16871 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16879 cls : 'fc-header-center',
16883 cls: 'fc-header-title',
16886 html : 'month / year'
16894 cls : 'fc-header-right',
16896 /* fc_button('month', 'left', '', 'month' ),
16897 fc_button('week', '', '', 'week' ),
16898 fc_button('day', 'right', '', 'day' )
16910 header = this.header;
16913 var cal_heads = function() {
16915 // fixme - handle this.
16917 for (var i =0; i < Date.dayNames.length; i++) {
16918 var d = Date.dayNames[i];
16921 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16922 html : d.substring(0,3)
16926 ret[0].cls += ' fc-first';
16927 ret[6].cls += ' fc-last';
16930 var cal_cell = function(n) {
16933 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16938 cls: 'fc-day-number',
16942 cls: 'fc-day-content',
16946 style: 'position: relative;' // height: 17px;
16958 var cal_rows = function() {
16961 for (var r = 0; r < 6; r++) {
16968 for (var i =0; i < Date.dayNames.length; i++) {
16969 var d = Date.dayNames[i];
16970 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16973 row.cn[0].cls+=' fc-first';
16974 row.cn[0].cn[0].style = 'min-height:90px';
16975 row.cn[6].cls+=' fc-last';
16979 ret[0].cls += ' fc-first';
16980 ret[4].cls += ' fc-prev-last';
16981 ret[5].cls += ' fc-last';
16988 cls: 'fc-border-separate',
16989 style : 'width:100%',
16997 cls : 'fc-first fc-last',
17015 cls : 'fc-content',
17016 style : "position: relative;",
17019 cls : 'fc-view fc-view-month fc-grid',
17020 style : 'position: relative',
17021 unselectable : 'on',
17024 cls : 'fc-event-container',
17025 style : 'position:absolute;z-index:8;top:0;left:0;'
17043 initEvents : function()
17046 throw "can not find store for calendar";
17052 style: "text-align:center",
17056 style: "background-color:white;width:50%;margin:250 auto",
17060 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17071 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17073 var size = this.el.select('.fc-content', true).first().getSize();
17074 this.maskEl.setSize(size.width, size.height);
17075 this.maskEl.enableDisplayMode("block");
17076 if(!this.loadMask){
17077 this.maskEl.hide();
17080 this.store = Roo.factory(this.store, Roo.data);
17081 this.store.on('load', this.onLoad, this);
17082 this.store.on('beforeload', this.onBeforeLoad, this);
17086 this.cells = this.el.select('.fc-day',true);
17087 //Roo.log(this.cells);
17088 this.textNodes = this.el.query('.fc-day-number');
17089 this.cells.addClassOnOver('fc-state-hover');
17091 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17092 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17093 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17094 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17096 this.on('monthchange', this.onMonthChange, this);
17098 this.update(new Date().clearTime());
17101 resize : function() {
17102 var sz = this.el.getSize();
17104 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17105 this.el.select('.fc-day-content div',true).setHeight(34);
17110 showPrevMonth : function(e){
17111 this.update(this.activeDate.add("mo", -1));
17113 showToday : function(e){
17114 this.update(new Date().clearTime());
17117 showNextMonth : function(e){
17118 this.update(this.activeDate.add("mo", 1));
17122 showPrevYear : function(){
17123 this.update(this.activeDate.add("y", -1));
17127 showNextYear : function(){
17128 this.update(this.activeDate.add("y", 1));
17133 update : function(date)
17135 var vd = this.activeDate;
17136 this.activeDate = date;
17137 // if(vd && this.el){
17138 // var t = date.getTime();
17139 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17140 // Roo.log('using add remove');
17142 // this.fireEvent('monthchange', this, date);
17144 // this.cells.removeClass("fc-state-highlight");
17145 // this.cells.each(function(c){
17146 // if(c.dateValue == t){
17147 // c.addClass("fc-state-highlight");
17148 // setTimeout(function(){
17149 // try{c.dom.firstChild.focus();}catch(e){}
17159 var days = date.getDaysInMonth();
17161 var firstOfMonth = date.getFirstDateOfMonth();
17162 var startingPos = firstOfMonth.getDay()-this.startDay;
17164 if(startingPos < this.startDay){
17168 var pm = date.add(Date.MONTH, -1);
17169 var prevStart = pm.getDaysInMonth()-startingPos;
17171 this.cells = this.el.select('.fc-day',true);
17172 this.textNodes = this.el.query('.fc-day-number');
17173 this.cells.addClassOnOver('fc-state-hover');
17175 var cells = this.cells.elements;
17176 var textEls = this.textNodes;
17178 Roo.each(cells, function(cell){
17179 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17182 days += startingPos;
17184 // convert everything to numbers so it's fast
17185 var day = 86400000;
17186 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17189 //Roo.log(prevStart);
17191 var today = new Date().clearTime().getTime();
17192 var sel = date.clearTime().getTime();
17193 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17194 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17195 var ddMatch = this.disabledDatesRE;
17196 var ddText = this.disabledDatesText;
17197 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17198 var ddaysText = this.disabledDaysText;
17199 var format = this.format;
17201 var setCellClass = function(cal, cell){
17205 //Roo.log('set Cell Class');
17207 var t = d.getTime();
17211 cell.dateValue = t;
17213 cell.className += " fc-today";
17214 cell.className += " fc-state-highlight";
17215 cell.title = cal.todayText;
17218 // disable highlight in other month..
17219 //cell.className += " fc-state-highlight";
17224 cell.className = " fc-state-disabled";
17225 cell.title = cal.minText;
17229 cell.className = " fc-state-disabled";
17230 cell.title = cal.maxText;
17234 if(ddays.indexOf(d.getDay()) != -1){
17235 cell.title = ddaysText;
17236 cell.className = " fc-state-disabled";
17239 if(ddMatch && format){
17240 var fvalue = d.dateFormat(format);
17241 if(ddMatch.test(fvalue)){
17242 cell.title = ddText.replace("%0", fvalue);
17243 cell.className = " fc-state-disabled";
17247 if (!cell.initialClassName) {
17248 cell.initialClassName = cell.dom.className;
17251 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17256 for(; i < startingPos; i++) {
17257 textEls[i].innerHTML = (++prevStart);
17258 d.setDate(d.getDate()+1);
17260 cells[i].className = "fc-past fc-other-month";
17261 setCellClass(this, cells[i]);
17266 for(; i < days; i++){
17267 intDay = i - startingPos + 1;
17268 textEls[i].innerHTML = (intDay);
17269 d.setDate(d.getDate()+1);
17271 cells[i].className = ''; // "x-date-active";
17272 setCellClass(this, cells[i]);
17276 for(; i < 42; i++) {
17277 textEls[i].innerHTML = (++extraDays);
17278 d.setDate(d.getDate()+1);
17280 cells[i].className = "fc-future fc-other-month";
17281 setCellClass(this, cells[i]);
17284 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17286 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17288 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17289 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17291 if(totalRows != 6){
17292 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17293 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17296 this.fireEvent('monthchange', this, date);
17300 if(!this.internalRender){
17301 var main = this.el.dom.firstChild;
17302 var w = main.offsetWidth;
17303 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17304 Roo.fly(main).setWidth(w);
17305 this.internalRender = true;
17306 // opera does not respect the auto grow header center column
17307 // then, after it gets a width opera refuses to recalculate
17308 // without a second pass
17309 if(Roo.isOpera && !this.secondPass){
17310 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17311 this.secondPass = true;
17312 this.update.defer(10, this, [date]);
17319 findCell : function(dt) {
17320 dt = dt.clearTime().getTime();
17322 this.cells.each(function(c){
17323 //Roo.log("check " +c.dateValue + '?=' + dt);
17324 if(c.dateValue == dt){
17334 findCells : function(ev) {
17335 var s = ev.start.clone().clearTime().getTime();
17337 var e= ev.end.clone().clearTime().getTime();
17340 this.cells.each(function(c){
17341 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17343 if(c.dateValue > e){
17346 if(c.dateValue < s){
17355 // findBestRow: function(cells)
17359 // for (var i =0 ; i < cells.length;i++) {
17360 // ret = Math.max(cells[i].rows || 0,ret);
17367 addItem : function(ev)
17369 // look for vertical location slot in
17370 var cells = this.findCells(ev);
17372 // ev.row = this.findBestRow(cells);
17374 // work out the location.
17378 for(var i =0; i < cells.length; i++) {
17380 cells[i].row = cells[0].row;
17383 cells[i].row = cells[i].row + 1;
17393 if (crow.start.getY() == cells[i].getY()) {
17395 crow.end = cells[i];
17412 cells[0].events.push(ev);
17414 this.calevents.push(ev);
17417 clearEvents: function() {
17419 if(!this.calevents){
17423 Roo.each(this.cells.elements, function(c){
17429 Roo.each(this.calevents, function(e) {
17430 Roo.each(e.els, function(el) {
17431 el.un('mouseenter' ,this.onEventEnter, this);
17432 el.un('mouseleave' ,this.onEventLeave, this);
17437 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17443 renderEvents: function()
17447 this.cells.each(function(c) {
17456 if(c.row != c.events.length){
17457 r = 4 - (4 - (c.row - c.events.length));
17460 c.events = ev.slice(0, r);
17461 c.more = ev.slice(r);
17463 if(c.more.length && c.more.length == 1){
17464 c.events.push(c.more.pop());
17467 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17471 this.cells.each(function(c) {
17473 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17476 for (var e = 0; e < c.events.length; e++){
17477 var ev = c.events[e];
17478 var rows = ev.rows;
17480 for(var i = 0; i < rows.length; i++) {
17482 // how many rows should it span..
17485 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17486 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17488 unselectable : "on",
17491 cls: 'fc-event-inner',
17495 // cls: 'fc-event-time',
17496 // html : cells.length > 1 ? '' : ev.time
17500 cls: 'fc-event-title',
17501 html : String.format('{0}', ev.title)
17508 cls: 'ui-resizable-handle ui-resizable-e',
17509 html : '  '
17516 cfg.cls += ' fc-event-start';
17518 if ((i+1) == rows.length) {
17519 cfg.cls += ' fc-event-end';
17522 var ctr = _this.el.select('.fc-event-container',true).first();
17523 var cg = ctr.createChild(cfg);
17525 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17526 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17528 var r = (c.more.length) ? 1 : 0;
17529 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17530 cg.setWidth(ebox.right - sbox.x -2);
17532 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17533 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17534 cg.on('click', _this.onEventClick, _this, ev);
17545 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17546 style : 'position: absolute',
17547 unselectable : "on",
17550 cls: 'fc-event-inner',
17554 cls: 'fc-event-title',
17562 cls: 'ui-resizable-handle ui-resizable-e',
17563 html : '  '
17569 var ctr = _this.el.select('.fc-event-container',true).first();
17570 var cg = ctr.createChild(cfg);
17572 var sbox = c.select('.fc-day-content',true).first().getBox();
17573 var ebox = c.select('.fc-day-content',true).first().getBox();
17575 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17576 cg.setWidth(ebox.right - sbox.x -2);
17578 cg.on('click', _this.onMoreEventClick, _this, c.more);
17588 onEventEnter: function (e, el,event,d) {
17589 this.fireEvent('evententer', this, el, event);
17592 onEventLeave: function (e, el,event,d) {
17593 this.fireEvent('eventleave', this, el, event);
17596 onEventClick: function (e, el,event,d) {
17597 this.fireEvent('eventclick', this, el, event);
17600 onMonthChange: function () {
17604 onMoreEventClick: function(e, el, more)
17608 this.calpopover.placement = 'right';
17609 this.calpopover.setTitle('More');
17611 this.calpopover.setContent('');
17613 var ctr = this.calpopover.el.select('.popover-content', true).first();
17615 Roo.each(more, function(m){
17617 cls : 'fc-event-hori fc-event-draggable',
17620 var cg = ctr.createChild(cfg);
17622 cg.on('click', _this.onEventClick, _this, m);
17625 this.calpopover.show(el);
17630 onLoad: function ()
17632 this.calevents = [];
17635 if(this.store.getCount() > 0){
17636 this.store.data.each(function(d){
17639 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17640 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17641 time : d.data.start_time,
17642 title : d.data.title,
17643 description : d.data.description,
17644 venue : d.data.venue
17649 this.renderEvents();
17651 if(this.calevents.length && this.loadMask){
17652 this.maskEl.hide();
17656 onBeforeLoad: function()
17658 this.clearEvents();
17660 this.maskEl.show();
17674 * @class Roo.bootstrap.Popover
17675 * @extends Roo.bootstrap.Component
17676 * Bootstrap Popover class
17677 * @cfg {String} html contents of the popover (or false to use children..)
17678 * @cfg {String} title of popover (or false to hide)
17679 * @cfg {String} placement how it is placed
17680 * @cfg {String} trigger click || hover (or false to trigger manually)
17681 * @cfg {String} over what (parent or false to trigger manually.)
17682 * @cfg {Number} delay - delay before showing
17685 * Create a new Popover
17686 * @param {Object} config The config object
17689 Roo.bootstrap.Popover = function(config){
17690 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17696 * After the popover show
17698 * @param {Roo.bootstrap.Popover} this
17703 * After the popover hide
17705 * @param {Roo.bootstrap.Popover} this
17711 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17713 title: 'Fill in a title',
17716 placement : 'right',
17717 trigger : 'hover', // hover
17723 can_build_overlaid : false,
17725 getChildContainer : function()
17727 return this.el.select('.popover-content',true).first();
17730 getAutoCreate : function(){
17733 cls : 'popover roo-dynamic',
17734 style: 'display:block',
17740 cls : 'popover-inner',
17744 cls: 'popover-title popover-header',
17748 cls : 'popover-content popover-body',
17759 setTitle: function(str)
17762 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17764 setContent: function(str)
17767 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17769 // as it get's added to the bottom of the page.
17770 onRender : function(ct, position)
17772 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17774 var cfg = Roo.apply({}, this.getAutoCreate());
17778 cfg.cls += ' ' + this.cls;
17781 cfg.style = this.style;
17783 //Roo.log("adding to ");
17784 this.el = Roo.get(document.body).createChild(cfg, position);
17785 // Roo.log(this.el);
17790 initEvents : function()
17792 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17793 this.el.enableDisplayMode('block');
17795 if (this.over === false) {
17798 if (this.triggers === false) {
17801 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17802 var triggers = this.trigger ? this.trigger.split(' ') : [];
17803 Roo.each(triggers, function(trigger) {
17805 if (trigger == 'click') {
17806 on_el.on('click', this.toggle, this);
17807 } else if (trigger != 'manual') {
17808 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17809 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17811 on_el.on(eventIn ,this.enter, this);
17812 on_el.on(eventOut, this.leave, this);
17823 toggle : function () {
17824 this.hoverState == 'in' ? this.leave() : this.enter();
17827 enter : function () {
17829 clearTimeout(this.timeout);
17831 this.hoverState = 'in';
17833 if (!this.delay || !this.delay.show) {
17838 this.timeout = setTimeout(function () {
17839 if (_t.hoverState == 'in') {
17842 }, this.delay.show)
17845 leave : function() {
17846 clearTimeout(this.timeout);
17848 this.hoverState = 'out';
17850 if (!this.delay || !this.delay.hide) {
17855 this.timeout = setTimeout(function () {
17856 if (_t.hoverState == 'out') {
17859 }, this.delay.hide)
17862 show : function (on_el)
17865 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17869 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17870 if (this.html !== false) {
17871 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17873 this.el.removeClass([
17874 'fade','top','bottom', 'left', 'right','in',
17875 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17877 if (!this.title.length) {
17878 this.el.select('.popover-title',true).hide();
17881 var placement = typeof this.placement == 'function' ?
17882 this.placement.call(this, this.el, on_el) :
17885 var autoToken = /\s?auto?\s?/i;
17886 var autoPlace = autoToken.test(placement);
17888 placement = placement.replace(autoToken, '') || 'top';
17892 //this.el.setXY([0,0]);
17894 this.el.dom.style.display='block';
17895 this.el.addClass(placement);
17897 //this.el.appendTo(on_el);
17899 var p = this.getPosition();
17900 var box = this.el.getBox();
17905 var align = Roo.bootstrap.Popover.alignment[placement];
17908 this.el.alignTo(on_el, align[0],align[1]);
17909 //var arrow = this.el.select('.arrow',true).first();
17910 //arrow.set(align[2],
17912 this.el.addClass('in');
17915 if (this.el.hasClass('fade')) {
17919 this.hoverState = 'in';
17921 this.fireEvent('show', this);
17926 this.el.setXY([0,0]);
17927 this.el.removeClass('in');
17929 this.hoverState = null;
17931 this.fireEvent('hide', this);
17936 Roo.bootstrap.Popover.alignment = {
17937 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17938 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17939 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17940 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17951 * @class Roo.bootstrap.Progress
17952 * @extends Roo.bootstrap.Component
17953 * Bootstrap Progress class
17954 * @cfg {Boolean} striped striped of the progress bar
17955 * @cfg {Boolean} active animated of the progress bar
17959 * Create a new Progress
17960 * @param {Object} config The config object
17963 Roo.bootstrap.Progress = function(config){
17964 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17967 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17972 getAutoCreate : function(){
17980 cfg.cls += ' progress-striped';
17984 cfg.cls += ' active';
18003 * @class Roo.bootstrap.ProgressBar
18004 * @extends Roo.bootstrap.Component
18005 * Bootstrap ProgressBar class
18006 * @cfg {Number} aria_valuenow aria-value now
18007 * @cfg {Number} aria_valuemin aria-value min
18008 * @cfg {Number} aria_valuemax aria-value max
18009 * @cfg {String} label label for the progress bar
18010 * @cfg {String} panel (success | info | warning | danger )
18011 * @cfg {String} role role of the progress bar
18012 * @cfg {String} sr_only text
18016 * Create a new ProgressBar
18017 * @param {Object} config The config object
18020 Roo.bootstrap.ProgressBar = function(config){
18021 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18024 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18028 aria_valuemax : 100,
18034 getAutoCreate : function()
18039 cls: 'progress-bar',
18040 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18052 cfg.role = this.role;
18055 if(this.aria_valuenow){
18056 cfg['aria-valuenow'] = this.aria_valuenow;
18059 if(this.aria_valuemin){
18060 cfg['aria-valuemin'] = this.aria_valuemin;
18063 if(this.aria_valuemax){
18064 cfg['aria-valuemax'] = this.aria_valuemax;
18067 if(this.label && !this.sr_only){
18068 cfg.html = this.label;
18072 cfg.cls += ' progress-bar-' + this.panel;
18078 update : function(aria_valuenow)
18080 this.aria_valuenow = aria_valuenow;
18082 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18097 * @class Roo.bootstrap.TabGroup
18098 * @extends Roo.bootstrap.Column
18099 * Bootstrap Column class
18100 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18101 * @cfg {Boolean} carousel true to make the group behave like a carousel
18102 * @cfg {Boolean} bullets show bullets for the panels
18103 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18104 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18105 * @cfg {Boolean} showarrow (true|false) show arrow default true
18108 * Create a new TabGroup
18109 * @param {Object} config The config object
18112 Roo.bootstrap.TabGroup = function(config){
18113 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18115 this.navId = Roo.id();
18118 Roo.bootstrap.TabGroup.register(this);
18122 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18125 transition : false,
18130 slideOnTouch : false,
18133 getAutoCreate : function()
18135 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18137 cfg.cls += ' tab-content';
18139 if (this.carousel) {
18140 cfg.cls += ' carousel slide';
18143 cls : 'carousel-inner',
18147 if(this.bullets && !Roo.isTouch){
18150 cls : 'carousel-bullets',
18154 if(this.bullets_cls){
18155 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18162 cfg.cn[0].cn.push(bullets);
18165 if(this.showarrow){
18166 cfg.cn[0].cn.push({
18168 class : 'carousel-arrow',
18172 class : 'carousel-prev',
18176 class : 'fa fa-chevron-left'
18182 class : 'carousel-next',
18186 class : 'fa fa-chevron-right'
18199 initEvents: function()
18201 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18202 // this.el.on("touchstart", this.onTouchStart, this);
18205 if(this.autoslide){
18208 this.slideFn = window.setInterval(function() {
18209 _this.showPanelNext();
18213 if(this.showarrow){
18214 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18215 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18221 // onTouchStart : function(e, el, o)
18223 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18227 // this.showPanelNext();
18231 getChildContainer : function()
18233 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18237 * register a Navigation item
18238 * @param {Roo.bootstrap.NavItem} the navitem to add
18240 register : function(item)
18242 this.tabs.push( item);
18243 item.navId = this.navId; // not really needed..
18248 getActivePanel : function()
18251 Roo.each(this.tabs, function(t) {
18261 getPanelByName : function(n)
18264 Roo.each(this.tabs, function(t) {
18265 if (t.tabId == n) {
18273 indexOfPanel : function(p)
18276 Roo.each(this.tabs, function(t,i) {
18277 if (t.tabId == p.tabId) {
18286 * show a specific panel
18287 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18288 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18290 showPanel : function (pan)
18292 if(this.transition || typeof(pan) == 'undefined'){
18293 Roo.log("waiting for the transitionend");
18297 if (typeof(pan) == 'number') {
18298 pan = this.tabs[pan];
18301 if (typeof(pan) == 'string') {
18302 pan = this.getPanelByName(pan);
18305 var cur = this.getActivePanel();
18308 Roo.log('pan or acitve pan is undefined');
18312 if (pan.tabId == this.getActivePanel().tabId) {
18316 if (false === cur.fireEvent('beforedeactivate')) {
18320 if(this.bullets > 0 && !Roo.isTouch){
18321 this.setActiveBullet(this.indexOfPanel(pan));
18324 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18326 this.transition = true;
18327 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18328 var lr = dir == 'next' ? 'left' : 'right';
18329 pan.el.addClass(dir); // or prev
18330 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18331 cur.el.addClass(lr); // or right
18332 pan.el.addClass(lr);
18335 cur.el.on('transitionend', function() {
18336 Roo.log("trans end?");
18338 pan.el.removeClass([lr,dir]);
18339 pan.setActive(true);
18341 cur.el.removeClass([lr]);
18342 cur.setActive(false);
18344 _this.transition = false;
18346 }, this, { single: true } );
18351 cur.setActive(false);
18352 pan.setActive(true);
18357 showPanelNext : function()
18359 var i = this.indexOfPanel(this.getActivePanel());
18361 if (i >= this.tabs.length - 1 && !this.autoslide) {
18365 if (i >= this.tabs.length - 1 && this.autoslide) {
18369 this.showPanel(this.tabs[i+1]);
18372 showPanelPrev : function()
18374 var i = this.indexOfPanel(this.getActivePanel());
18376 if (i < 1 && !this.autoslide) {
18380 if (i < 1 && this.autoslide) {
18381 i = this.tabs.length;
18384 this.showPanel(this.tabs[i-1]);
18388 addBullet: function()
18390 if(!this.bullets || Roo.isTouch){
18393 var ctr = this.el.select('.carousel-bullets',true).first();
18394 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18395 var bullet = ctr.createChild({
18396 cls : 'bullet bullet-' + i
18397 },ctr.dom.lastChild);
18402 bullet.on('click', (function(e, el, o, ii, t){
18404 e.preventDefault();
18406 this.showPanel(ii);
18408 if(this.autoslide && this.slideFn){
18409 clearInterval(this.slideFn);
18410 this.slideFn = window.setInterval(function() {
18411 _this.showPanelNext();
18415 }).createDelegate(this, [i, bullet], true));
18420 setActiveBullet : function(i)
18426 Roo.each(this.el.select('.bullet', true).elements, function(el){
18427 el.removeClass('selected');
18430 var bullet = this.el.select('.bullet-' + i, true).first();
18436 bullet.addClass('selected');
18447 Roo.apply(Roo.bootstrap.TabGroup, {
18451 * register a Navigation Group
18452 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18454 register : function(navgrp)
18456 this.groups[navgrp.navId] = navgrp;
18460 * fetch a Navigation Group based on the navigation ID
18461 * if one does not exist , it will get created.
18462 * @param {string} the navgroup to add
18463 * @returns {Roo.bootstrap.NavGroup} the navgroup
18465 get: function(navId) {
18466 if (typeof(this.groups[navId]) == 'undefined') {
18467 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18469 return this.groups[navId] ;
18484 * @class Roo.bootstrap.TabPanel
18485 * @extends Roo.bootstrap.Component
18486 * Bootstrap TabPanel class
18487 * @cfg {Boolean} active panel active
18488 * @cfg {String} html panel content
18489 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18490 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18491 * @cfg {String} href click to link..
18495 * Create a new TabPanel
18496 * @param {Object} config The config object
18499 Roo.bootstrap.TabPanel = function(config){
18500 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18504 * Fires when the active status changes
18505 * @param {Roo.bootstrap.TabPanel} this
18506 * @param {Boolean} state the new state
18511 * @event beforedeactivate
18512 * Fires before a tab is de-activated - can be used to do validation on a form.
18513 * @param {Roo.bootstrap.TabPanel} this
18514 * @return {Boolean} false if there is an error
18517 'beforedeactivate': true
18520 this.tabId = this.tabId || Roo.id();
18524 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18532 getAutoCreate : function(){
18535 // item is needed for carousel - not sure if it has any effect otherwise
18536 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18537 html: this.html || ''
18541 cfg.cls += ' active';
18545 cfg.tabId = this.tabId;
18552 initEvents: function()
18554 var p = this.parent();
18556 this.navId = this.navId || p.navId;
18558 if (typeof(this.navId) != 'undefined') {
18559 // not really needed.. but just in case.. parent should be a NavGroup.
18560 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18564 var i = tg.tabs.length - 1;
18566 if(this.active && tg.bullets > 0 && i < tg.bullets){
18567 tg.setActiveBullet(i);
18571 this.el.on('click', this.onClick, this);
18574 this.el.on("touchstart", this.onTouchStart, this);
18575 this.el.on("touchmove", this.onTouchMove, this);
18576 this.el.on("touchend", this.onTouchEnd, this);
18581 onRender : function(ct, position)
18583 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18586 setActive : function(state)
18588 Roo.log("panel - set active " + this.tabId + "=" + state);
18590 this.active = state;
18592 this.el.removeClass('active');
18594 } else if (!this.el.hasClass('active')) {
18595 this.el.addClass('active');
18598 this.fireEvent('changed', this, state);
18601 onClick : function(e)
18603 e.preventDefault();
18605 if(!this.href.length){
18609 window.location.href = this.href;
18618 onTouchStart : function(e)
18620 this.swiping = false;
18622 this.startX = e.browserEvent.touches[0].clientX;
18623 this.startY = e.browserEvent.touches[0].clientY;
18626 onTouchMove : function(e)
18628 this.swiping = true;
18630 this.endX = e.browserEvent.touches[0].clientX;
18631 this.endY = e.browserEvent.touches[0].clientY;
18634 onTouchEnd : function(e)
18641 var tabGroup = this.parent();
18643 if(this.endX > this.startX){ // swiping right
18644 tabGroup.showPanelPrev();
18648 if(this.startX > this.endX){ // swiping left
18649 tabGroup.showPanelNext();
18668 * @class Roo.bootstrap.DateField
18669 * @extends Roo.bootstrap.Input
18670 * Bootstrap DateField class
18671 * @cfg {Number} weekStart default 0
18672 * @cfg {String} viewMode default empty, (months|years)
18673 * @cfg {String} minViewMode default empty, (months|years)
18674 * @cfg {Number} startDate default -Infinity
18675 * @cfg {Number} endDate default Infinity
18676 * @cfg {Boolean} todayHighlight default false
18677 * @cfg {Boolean} todayBtn default false
18678 * @cfg {Boolean} calendarWeeks default false
18679 * @cfg {Object} daysOfWeekDisabled default empty
18680 * @cfg {Boolean} singleMode default false (true | false)
18682 * @cfg {Boolean} keyboardNavigation default true
18683 * @cfg {String} language default en
18686 * Create a new DateField
18687 * @param {Object} config The config object
18690 Roo.bootstrap.DateField = function(config){
18691 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18695 * Fires when this field show.
18696 * @param {Roo.bootstrap.DateField} this
18697 * @param {Mixed} date The date value
18702 * Fires when this field hide.
18703 * @param {Roo.bootstrap.DateField} this
18704 * @param {Mixed} date The date value
18709 * Fires when select a date.
18710 * @param {Roo.bootstrap.DateField} this
18711 * @param {Mixed} date The date value
18715 * @event beforeselect
18716 * Fires when before select a date.
18717 * @param {Roo.bootstrap.DateField} this
18718 * @param {Mixed} date The date value
18720 beforeselect : true
18724 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18727 * @cfg {String} format
18728 * The default date format string which can be overriden for localization support. The format must be
18729 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18733 * @cfg {String} altFormats
18734 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18735 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18737 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18745 todayHighlight : false,
18751 keyboardNavigation: true,
18753 calendarWeeks: false,
18755 startDate: -Infinity,
18759 daysOfWeekDisabled: [],
18763 singleMode : false,
18765 UTCDate: function()
18767 return new Date(Date.UTC.apply(Date, arguments));
18770 UTCToday: function()
18772 var today = new Date();
18773 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18776 getDate: function() {
18777 var d = this.getUTCDate();
18778 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18781 getUTCDate: function() {
18785 setDate: function(d) {
18786 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18789 setUTCDate: function(d) {
18791 this.setValue(this.formatDate(this.date));
18794 onRender: function(ct, position)
18797 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18799 this.language = this.language || 'en';
18800 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18801 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18803 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18804 this.format = this.format || 'm/d/y';
18805 this.isInline = false;
18806 this.isInput = true;
18807 this.component = this.el.select('.add-on', true).first() || false;
18808 this.component = (this.component && this.component.length === 0) ? false : this.component;
18809 this.hasInput = this.component && this.inputEl().length;
18811 if (typeof(this.minViewMode === 'string')) {
18812 switch (this.minViewMode) {
18814 this.minViewMode = 1;
18817 this.minViewMode = 2;
18820 this.minViewMode = 0;
18825 if (typeof(this.viewMode === 'string')) {
18826 switch (this.viewMode) {
18839 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18841 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18843 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18845 this.picker().on('mousedown', this.onMousedown, this);
18846 this.picker().on('click', this.onClick, this);
18848 this.picker().addClass('datepicker-dropdown');
18850 this.startViewMode = this.viewMode;
18852 if(this.singleMode){
18853 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18854 v.setVisibilityMode(Roo.Element.DISPLAY);
18858 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18859 v.setStyle('width', '189px');
18863 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18864 if(!this.calendarWeeks){
18869 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18870 v.attr('colspan', function(i, val){
18871 return parseInt(val) + 1;
18876 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18878 this.setStartDate(this.startDate);
18879 this.setEndDate(this.endDate);
18881 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18888 if(this.isInline) {
18893 picker : function()
18895 return this.pickerEl;
18896 // return this.el.select('.datepicker', true).first();
18899 fillDow: function()
18901 var dowCnt = this.weekStart;
18910 if(this.calendarWeeks){
18918 while (dowCnt < this.weekStart + 7) {
18922 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18926 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18929 fillMonths: function()
18932 var months = this.picker().select('>.datepicker-months td', true).first();
18934 months.dom.innerHTML = '';
18940 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18943 months.createChild(month);
18950 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;
18952 if (this.date < this.startDate) {
18953 this.viewDate = new Date(this.startDate);
18954 } else if (this.date > this.endDate) {
18955 this.viewDate = new Date(this.endDate);
18957 this.viewDate = new Date(this.date);
18965 var d = new Date(this.viewDate),
18966 year = d.getUTCFullYear(),
18967 month = d.getUTCMonth(),
18968 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18969 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18970 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18971 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18972 currentDate = this.date && this.date.valueOf(),
18973 today = this.UTCToday();
18975 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18977 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18979 // this.picker.select('>tfoot th.today').
18980 // .text(dates[this.language].today)
18981 // .toggle(this.todayBtn !== false);
18983 this.updateNavArrows();
18986 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18988 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18990 prevMonth.setUTCDate(day);
18992 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18994 var nextMonth = new Date(prevMonth);
18996 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18998 nextMonth = nextMonth.valueOf();
19000 var fillMonths = false;
19002 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19004 while(prevMonth.valueOf() <= nextMonth) {
19007 if (prevMonth.getUTCDay() === this.weekStart) {
19009 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19017 if(this.calendarWeeks){
19018 // ISO 8601: First week contains first thursday.
19019 // ISO also states week starts on Monday, but we can be more abstract here.
19021 // Start of current week: based on weekstart/current date
19022 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19023 // Thursday of this week
19024 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19025 // First Thursday of year, year from thursday
19026 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19027 // Calendar week: ms between thursdays, div ms per day, div 7 days
19028 calWeek = (th - yth) / 864e5 / 7 + 1;
19030 fillMonths.cn.push({
19038 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19040 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19043 if (this.todayHighlight &&
19044 prevMonth.getUTCFullYear() == today.getFullYear() &&
19045 prevMonth.getUTCMonth() == today.getMonth() &&
19046 prevMonth.getUTCDate() == today.getDate()) {
19047 clsName += ' today';
19050 if (currentDate && prevMonth.valueOf() === currentDate) {
19051 clsName += ' active';
19054 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19055 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19056 clsName += ' disabled';
19059 fillMonths.cn.push({
19061 cls: 'day ' + clsName,
19062 html: prevMonth.getDate()
19065 prevMonth.setDate(prevMonth.getDate()+1);
19068 var currentYear = this.date && this.date.getUTCFullYear();
19069 var currentMonth = this.date && this.date.getUTCMonth();
19071 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19073 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19074 v.removeClass('active');
19076 if(currentYear === year && k === currentMonth){
19077 v.addClass('active');
19080 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19081 v.addClass('disabled');
19087 year = parseInt(year/10, 10) * 10;
19089 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19091 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19094 for (var i = -1; i < 11; i++) {
19095 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19097 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19105 showMode: function(dir)
19108 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19111 Roo.each(this.picker().select('>div',true).elements, function(v){
19112 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19115 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19120 if(this.isInline) {
19124 this.picker().removeClass(['bottom', 'top']);
19126 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19128 * place to the top of element!
19132 this.picker().addClass('top');
19133 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19138 this.picker().addClass('bottom');
19140 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19143 parseDate : function(value)
19145 if(!value || value instanceof Date){
19148 var v = Date.parseDate(value, this.format);
19149 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19150 v = Date.parseDate(value, 'Y-m-d');
19152 if(!v && this.altFormats){
19153 if(!this.altFormatsArray){
19154 this.altFormatsArray = this.altFormats.split("|");
19156 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19157 v = Date.parseDate(value, this.altFormatsArray[i]);
19163 formatDate : function(date, fmt)
19165 return (!date || !(date instanceof Date)) ?
19166 date : date.dateFormat(fmt || this.format);
19169 onFocus : function()
19171 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19175 onBlur : function()
19177 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19179 var d = this.inputEl().getValue();
19186 showPopup : function()
19188 this.picker().show();
19192 this.fireEvent('showpopup', this, this.date);
19195 hidePopup : function()
19197 if(this.isInline) {
19200 this.picker().hide();
19201 this.viewMode = this.startViewMode;
19204 this.fireEvent('hidepopup', this, this.date);
19208 onMousedown: function(e)
19210 e.stopPropagation();
19211 e.preventDefault();
19216 Roo.bootstrap.DateField.superclass.keyup.call(this);
19220 setValue: function(v)
19222 if(this.fireEvent('beforeselect', this, v) !== false){
19223 var d = new Date(this.parseDate(v) ).clearTime();
19225 if(isNaN(d.getTime())){
19226 this.date = this.viewDate = '';
19227 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19231 v = this.formatDate(d);
19233 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19235 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19239 this.fireEvent('select', this, this.date);
19243 getValue: function()
19245 return this.formatDate(this.date);
19248 fireKey: function(e)
19250 if (!this.picker().isVisible()){
19251 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19257 var dateChanged = false,
19259 newDate, newViewDate;
19264 e.preventDefault();
19268 if (!this.keyboardNavigation) {
19271 dir = e.keyCode == 37 ? -1 : 1;
19274 newDate = this.moveYear(this.date, dir);
19275 newViewDate = this.moveYear(this.viewDate, dir);
19276 } else if (e.shiftKey){
19277 newDate = this.moveMonth(this.date, dir);
19278 newViewDate = this.moveMonth(this.viewDate, dir);
19280 newDate = new Date(this.date);
19281 newDate.setUTCDate(this.date.getUTCDate() + dir);
19282 newViewDate = new Date(this.viewDate);
19283 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19285 if (this.dateWithinRange(newDate)){
19286 this.date = newDate;
19287 this.viewDate = newViewDate;
19288 this.setValue(this.formatDate(this.date));
19290 e.preventDefault();
19291 dateChanged = true;
19296 if (!this.keyboardNavigation) {
19299 dir = e.keyCode == 38 ? -1 : 1;
19301 newDate = this.moveYear(this.date, dir);
19302 newViewDate = this.moveYear(this.viewDate, dir);
19303 } else if (e.shiftKey){
19304 newDate = this.moveMonth(this.date, dir);
19305 newViewDate = this.moveMonth(this.viewDate, dir);
19307 newDate = new Date(this.date);
19308 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19309 newViewDate = new Date(this.viewDate);
19310 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19312 if (this.dateWithinRange(newDate)){
19313 this.date = newDate;
19314 this.viewDate = newViewDate;
19315 this.setValue(this.formatDate(this.date));
19317 e.preventDefault();
19318 dateChanged = true;
19322 this.setValue(this.formatDate(this.date));
19324 e.preventDefault();
19327 this.setValue(this.formatDate(this.date));
19341 onClick: function(e)
19343 e.stopPropagation();
19344 e.preventDefault();
19346 var target = e.getTarget();
19348 if(target.nodeName.toLowerCase() === 'i'){
19349 target = Roo.get(target).dom.parentNode;
19352 var nodeName = target.nodeName;
19353 var className = target.className;
19354 var html = target.innerHTML;
19355 //Roo.log(nodeName);
19357 switch(nodeName.toLowerCase()) {
19359 switch(className) {
19365 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19366 switch(this.viewMode){
19368 this.viewDate = this.moveMonth(this.viewDate, dir);
19372 this.viewDate = this.moveYear(this.viewDate, dir);
19378 var date = new Date();
19379 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19381 this.setValue(this.formatDate(this.date));
19388 if (className.indexOf('disabled') < 0) {
19389 this.viewDate.setUTCDate(1);
19390 if (className.indexOf('month') > -1) {
19391 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19393 var year = parseInt(html, 10) || 0;
19394 this.viewDate.setUTCFullYear(year);
19398 if(this.singleMode){
19399 this.setValue(this.formatDate(this.viewDate));
19410 //Roo.log(className);
19411 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19412 var day = parseInt(html, 10) || 1;
19413 var year = this.viewDate.getUTCFullYear(),
19414 month = this.viewDate.getUTCMonth();
19416 if (className.indexOf('old') > -1) {
19423 } else if (className.indexOf('new') > -1) {
19431 //Roo.log([year,month,day]);
19432 this.date = this.UTCDate(year, month, day,0,0,0,0);
19433 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19435 //Roo.log(this.formatDate(this.date));
19436 this.setValue(this.formatDate(this.date));
19443 setStartDate: function(startDate)
19445 this.startDate = startDate || -Infinity;
19446 if (this.startDate !== -Infinity) {
19447 this.startDate = this.parseDate(this.startDate);
19450 this.updateNavArrows();
19453 setEndDate: function(endDate)
19455 this.endDate = endDate || Infinity;
19456 if (this.endDate !== Infinity) {
19457 this.endDate = this.parseDate(this.endDate);
19460 this.updateNavArrows();
19463 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19465 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19466 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19467 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19469 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19470 return parseInt(d, 10);
19473 this.updateNavArrows();
19476 updateNavArrows: function()
19478 if(this.singleMode){
19482 var d = new Date(this.viewDate),
19483 year = d.getUTCFullYear(),
19484 month = d.getUTCMonth();
19486 Roo.each(this.picker().select('.prev', true).elements, function(v){
19488 switch (this.viewMode) {
19491 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19497 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19504 Roo.each(this.picker().select('.next', true).elements, function(v){
19506 switch (this.viewMode) {
19509 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19515 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19523 moveMonth: function(date, dir)
19528 var new_date = new Date(date.valueOf()),
19529 day = new_date.getUTCDate(),
19530 month = new_date.getUTCMonth(),
19531 mag = Math.abs(dir),
19533 dir = dir > 0 ? 1 : -1;
19536 // If going back one month, make sure month is not current month
19537 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19539 return new_date.getUTCMonth() == month;
19541 // If going forward one month, make sure month is as expected
19542 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19544 return new_date.getUTCMonth() != new_month;
19546 new_month = month + dir;
19547 new_date.setUTCMonth(new_month);
19548 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19549 if (new_month < 0 || new_month > 11) {
19550 new_month = (new_month + 12) % 12;
19553 // For magnitudes >1, move one month at a time...
19554 for (var i=0; i<mag; i++) {
19555 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19556 new_date = this.moveMonth(new_date, dir);
19558 // ...then reset the day, keeping it in the new month
19559 new_month = new_date.getUTCMonth();
19560 new_date.setUTCDate(day);
19562 return new_month != new_date.getUTCMonth();
19565 // Common date-resetting loop -- if date is beyond end of month, make it
19568 new_date.setUTCDate(--day);
19569 new_date.setUTCMonth(new_month);
19574 moveYear: function(date, dir)
19576 return this.moveMonth(date, dir*12);
19579 dateWithinRange: function(date)
19581 return date >= this.startDate && date <= this.endDate;
19587 this.picker().remove();
19590 validateValue : function(value)
19592 if(this.getVisibilityEl().hasClass('hidden')){
19596 if(value.length < 1) {
19597 if(this.allowBlank){
19603 if(value.length < this.minLength){
19606 if(value.length > this.maxLength){
19610 var vt = Roo.form.VTypes;
19611 if(!vt[this.vtype](value, this)){
19615 if(typeof this.validator == "function"){
19616 var msg = this.validator(value);
19622 if(this.regex && !this.regex.test(value)){
19626 if(typeof(this.parseDate(value)) == 'undefined'){
19630 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19634 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19644 this.date = this.viewDate = '';
19646 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19651 Roo.apply(Roo.bootstrap.DateField, {
19662 html: '<i class="fa fa-arrow-left"/>'
19672 html: '<i class="fa fa-arrow-right"/>'
19714 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19715 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19716 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19717 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19718 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19731 navFnc: 'FullYear',
19736 navFnc: 'FullYear',
19741 Roo.apply(Roo.bootstrap.DateField, {
19745 cls: 'datepicker dropdown-menu roo-dynamic',
19749 cls: 'datepicker-days',
19753 cls: 'table-condensed',
19755 Roo.bootstrap.DateField.head,
19759 Roo.bootstrap.DateField.footer
19766 cls: 'datepicker-months',
19770 cls: 'table-condensed',
19772 Roo.bootstrap.DateField.head,
19773 Roo.bootstrap.DateField.content,
19774 Roo.bootstrap.DateField.footer
19781 cls: 'datepicker-years',
19785 cls: 'table-condensed',
19787 Roo.bootstrap.DateField.head,
19788 Roo.bootstrap.DateField.content,
19789 Roo.bootstrap.DateField.footer
19808 * @class Roo.bootstrap.TimeField
19809 * @extends Roo.bootstrap.Input
19810 * Bootstrap DateField class
19814 * Create a new TimeField
19815 * @param {Object} config The config object
19818 Roo.bootstrap.TimeField = function(config){
19819 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19823 * Fires when this field show.
19824 * @param {Roo.bootstrap.DateField} thisthis
19825 * @param {Mixed} date The date value
19830 * Fires when this field hide.
19831 * @param {Roo.bootstrap.DateField} this
19832 * @param {Mixed} date The date value
19837 * Fires when select a date.
19838 * @param {Roo.bootstrap.DateField} this
19839 * @param {Mixed} date The date value
19845 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19848 * @cfg {String} format
19849 * The default time format string which can be overriden for localization support. The format must be
19850 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19854 onRender: function(ct, position)
19857 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19859 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19861 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19863 this.pop = this.picker().select('>.datepicker-time',true).first();
19864 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19866 this.picker().on('mousedown', this.onMousedown, this);
19867 this.picker().on('click', this.onClick, this);
19869 this.picker().addClass('datepicker-dropdown');
19874 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19875 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19876 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19877 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19878 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19879 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19883 fireKey: function(e){
19884 if (!this.picker().isVisible()){
19885 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19891 e.preventDefault();
19899 this.onTogglePeriod();
19902 this.onIncrementMinutes();
19905 this.onDecrementMinutes();
19914 onClick: function(e) {
19915 e.stopPropagation();
19916 e.preventDefault();
19919 picker : function()
19921 return this.el.select('.datepicker', true).first();
19924 fillTime: function()
19926 var time = this.pop.select('tbody', true).first();
19928 time.dom.innerHTML = '';
19943 cls: 'hours-up glyphicon glyphicon-chevron-up'
19963 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19984 cls: 'timepicker-hour',
19999 cls: 'timepicker-minute',
20014 cls: 'btn btn-primary period',
20036 cls: 'hours-down glyphicon glyphicon-chevron-down'
20056 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20074 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20081 var hours = this.time.getHours();
20082 var minutes = this.time.getMinutes();
20095 hours = hours - 12;
20099 hours = '0' + hours;
20103 minutes = '0' + minutes;
20106 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20107 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20108 this.pop.select('button', true).first().dom.innerHTML = period;
20114 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20116 var cls = ['bottom'];
20118 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20125 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20130 this.picker().addClass(cls.join('-'));
20134 Roo.each(cls, function(c){
20136 _this.picker().setTop(_this.inputEl().getHeight());
20140 _this.picker().setTop(0 - _this.picker().getHeight());
20145 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20149 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20156 onFocus : function()
20158 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20162 onBlur : function()
20164 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20170 this.picker().show();
20175 this.fireEvent('show', this, this.date);
20180 this.picker().hide();
20183 this.fireEvent('hide', this, this.date);
20186 setTime : function()
20189 this.setValue(this.time.format(this.format));
20191 this.fireEvent('select', this, this.date);
20196 onMousedown: function(e){
20197 e.stopPropagation();
20198 e.preventDefault();
20201 onIncrementHours: function()
20203 Roo.log('onIncrementHours');
20204 this.time = this.time.add(Date.HOUR, 1);
20209 onDecrementHours: function()
20211 Roo.log('onDecrementHours');
20212 this.time = this.time.add(Date.HOUR, -1);
20216 onIncrementMinutes: function()
20218 Roo.log('onIncrementMinutes');
20219 this.time = this.time.add(Date.MINUTE, 1);
20223 onDecrementMinutes: function()
20225 Roo.log('onDecrementMinutes');
20226 this.time = this.time.add(Date.MINUTE, -1);
20230 onTogglePeriod: function()
20232 Roo.log('onTogglePeriod');
20233 this.time = this.time.add(Date.HOUR, 12);
20240 Roo.apply(Roo.bootstrap.TimeField, {
20270 cls: 'btn btn-info ok',
20282 Roo.apply(Roo.bootstrap.TimeField, {
20286 cls: 'datepicker dropdown-menu',
20290 cls: 'datepicker-time',
20294 cls: 'table-condensed',
20296 Roo.bootstrap.TimeField.content,
20297 Roo.bootstrap.TimeField.footer
20316 * @class Roo.bootstrap.MonthField
20317 * @extends Roo.bootstrap.Input
20318 * Bootstrap MonthField class
20320 * @cfg {String} language default en
20323 * Create a new MonthField
20324 * @param {Object} config The config object
20327 Roo.bootstrap.MonthField = function(config){
20328 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20333 * Fires when this field show.
20334 * @param {Roo.bootstrap.MonthField} this
20335 * @param {Mixed} date The date value
20340 * Fires when this field hide.
20341 * @param {Roo.bootstrap.MonthField} this
20342 * @param {Mixed} date The date value
20347 * Fires when select a date.
20348 * @param {Roo.bootstrap.MonthField} this
20349 * @param {String} oldvalue The old value
20350 * @param {String} newvalue The new value
20356 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20358 onRender: function(ct, position)
20361 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20363 this.language = this.language || 'en';
20364 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20365 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20367 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20368 this.isInline = false;
20369 this.isInput = true;
20370 this.component = this.el.select('.add-on', true).first() || false;
20371 this.component = (this.component && this.component.length === 0) ? false : this.component;
20372 this.hasInput = this.component && this.inputEL().length;
20374 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20376 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20378 this.picker().on('mousedown', this.onMousedown, this);
20379 this.picker().on('click', this.onClick, this);
20381 this.picker().addClass('datepicker-dropdown');
20383 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20384 v.setStyle('width', '189px');
20391 if(this.isInline) {
20397 setValue: function(v, suppressEvent)
20399 var o = this.getValue();
20401 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20405 if(suppressEvent !== true){
20406 this.fireEvent('select', this, o, v);
20411 getValue: function()
20416 onClick: function(e)
20418 e.stopPropagation();
20419 e.preventDefault();
20421 var target = e.getTarget();
20423 if(target.nodeName.toLowerCase() === 'i'){
20424 target = Roo.get(target).dom.parentNode;
20427 var nodeName = target.nodeName;
20428 var className = target.className;
20429 var html = target.innerHTML;
20431 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20435 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20437 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20443 picker : function()
20445 return this.pickerEl;
20448 fillMonths: function()
20451 var months = this.picker().select('>.datepicker-months td', true).first();
20453 months.dom.innerHTML = '';
20459 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20462 months.createChild(month);
20471 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20472 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20475 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20476 e.removeClass('active');
20478 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20479 e.addClass('active');
20486 if(this.isInline) {
20490 this.picker().removeClass(['bottom', 'top']);
20492 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20494 * place to the top of element!
20498 this.picker().addClass('top');
20499 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20504 this.picker().addClass('bottom');
20506 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20509 onFocus : function()
20511 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20515 onBlur : function()
20517 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20519 var d = this.inputEl().getValue();
20528 this.picker().show();
20529 this.picker().select('>.datepicker-months', true).first().show();
20533 this.fireEvent('show', this, this.date);
20538 if(this.isInline) {
20541 this.picker().hide();
20542 this.fireEvent('hide', this, this.date);
20546 onMousedown: function(e)
20548 e.stopPropagation();
20549 e.preventDefault();
20554 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20558 fireKey: function(e)
20560 if (!this.picker().isVisible()){
20561 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20572 e.preventDefault();
20576 dir = e.keyCode == 37 ? -1 : 1;
20578 this.vIndex = this.vIndex + dir;
20580 if(this.vIndex < 0){
20584 if(this.vIndex > 11){
20588 if(isNaN(this.vIndex)){
20592 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20598 dir = e.keyCode == 38 ? -1 : 1;
20600 this.vIndex = this.vIndex + dir * 4;
20602 if(this.vIndex < 0){
20606 if(this.vIndex > 11){
20610 if(isNaN(this.vIndex)){
20614 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20619 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20620 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20624 e.preventDefault();
20627 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20628 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20644 this.picker().remove();
20649 Roo.apply(Roo.bootstrap.MonthField, {
20668 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20669 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20674 Roo.apply(Roo.bootstrap.MonthField, {
20678 cls: 'datepicker dropdown-menu roo-dynamic',
20682 cls: 'datepicker-months',
20686 cls: 'table-condensed',
20688 Roo.bootstrap.DateField.content
20708 * @class Roo.bootstrap.CheckBox
20709 * @extends Roo.bootstrap.Input
20710 * Bootstrap CheckBox class
20712 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20713 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20714 * @cfg {String} boxLabel The text that appears beside the checkbox
20715 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20716 * @cfg {Boolean} checked initnal the element
20717 * @cfg {Boolean} inline inline the element (default false)
20718 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20719 * @cfg {String} tooltip label tooltip
20722 * Create a new CheckBox
20723 * @param {Object} config The config object
20726 Roo.bootstrap.CheckBox = function(config){
20727 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20732 * Fires when the element is checked or unchecked.
20733 * @param {Roo.bootstrap.CheckBox} this This input
20734 * @param {Boolean} checked The new checked value
20739 * Fires when the element is click.
20740 * @param {Roo.bootstrap.CheckBox} this This input
20747 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20749 inputType: 'checkbox',
20758 getAutoCreate : function()
20760 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20766 cfg.cls = 'form-group ' + this.inputType; //input-group
20769 cfg.cls += ' ' + this.inputType + '-inline';
20775 type : this.inputType,
20776 value : this.inputValue,
20777 cls : 'roo-' + this.inputType, //'form-box',
20778 placeholder : this.placeholder || ''
20782 if(this.inputType != 'radio'){
20786 cls : 'roo-hidden-value',
20787 value : this.checked ? this.inputValue : this.valueOff
20792 if (this.weight) { // Validity check?
20793 cfg.cls += " " + this.inputType + "-" + this.weight;
20796 if (this.disabled) {
20797 input.disabled=true;
20801 input.checked = this.checked;
20806 input.name = this.name;
20808 if(this.inputType != 'radio'){
20809 hidden.name = this.name;
20810 input.name = '_hidden_' + this.name;
20815 input.cls += ' input-' + this.size;
20820 ['xs','sm','md','lg'].map(function(size){
20821 if (settings[size]) {
20822 cfg.cls += ' col-' + size + '-' + settings[size];
20826 var inputblock = input;
20828 if (this.before || this.after) {
20831 cls : 'input-group',
20836 inputblock.cn.push({
20838 cls : 'input-group-addon',
20843 inputblock.cn.push(input);
20845 if(this.inputType != 'radio'){
20846 inputblock.cn.push(hidden);
20850 inputblock.cn.push({
20852 cls : 'input-group-addon',
20859 if (align ==='left' && this.fieldLabel.length) {
20860 // Roo.log("left and has label");
20865 cls : 'control-label',
20866 html : this.fieldLabel
20876 if(this.labelWidth > 12){
20877 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20880 if(this.labelWidth < 13 && this.labelmd == 0){
20881 this.labelmd = this.labelWidth;
20884 if(this.labellg > 0){
20885 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20886 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20889 if(this.labelmd > 0){
20890 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20891 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20894 if(this.labelsm > 0){
20895 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20896 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20899 if(this.labelxs > 0){
20900 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20901 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20904 } else if ( this.fieldLabel.length) {
20905 // Roo.log(" label");
20909 tag: this.boxLabel ? 'span' : 'label',
20911 cls: 'control-label box-input-label',
20912 //cls : 'input-group-addon',
20913 html : this.fieldLabel
20922 // Roo.log(" no label && no align");
20923 cfg.cn = [ inputblock ] ;
20929 var boxLabelCfg = {
20931 //'for': id, // box label is handled by onclick - so no for...
20933 html: this.boxLabel
20937 boxLabelCfg.tooltip = this.tooltip;
20940 cfg.cn.push(boxLabelCfg);
20943 if(this.inputType != 'radio'){
20944 cfg.cn.push(hidden);
20952 * return the real input element.
20954 inputEl: function ()
20956 return this.el.select('input.roo-' + this.inputType,true).first();
20958 hiddenEl: function ()
20960 return this.el.select('input.roo-hidden-value',true).first();
20963 labelEl: function()
20965 return this.el.select('label.control-label',true).first();
20967 /* depricated... */
20971 return this.labelEl();
20974 boxLabelEl: function()
20976 return this.el.select('label.box-label',true).first();
20979 initEvents : function()
20981 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20983 this.inputEl().on('click', this.onClick, this);
20985 if (this.boxLabel) {
20986 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20989 this.startValue = this.getValue();
20992 Roo.bootstrap.CheckBox.register(this);
20996 onClick : function(e)
20998 if(this.fireEvent('click', this, e) !== false){
20999 this.setChecked(!this.checked);
21004 setChecked : function(state,suppressEvent)
21006 this.startValue = this.getValue();
21008 if(this.inputType == 'radio'){
21010 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21011 e.dom.checked = false;
21014 this.inputEl().dom.checked = true;
21016 this.inputEl().dom.value = this.inputValue;
21018 if(suppressEvent !== true){
21019 this.fireEvent('check', this, true);
21027 this.checked = state;
21029 this.inputEl().dom.checked = state;
21032 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21034 if(suppressEvent !== true){
21035 this.fireEvent('check', this, state);
21041 getValue : function()
21043 if(this.inputType == 'radio'){
21044 return this.getGroupValue();
21047 return this.hiddenEl().dom.value;
21051 getGroupValue : function()
21053 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21057 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21060 setValue : function(v,suppressEvent)
21062 if(this.inputType == 'radio'){
21063 this.setGroupValue(v, suppressEvent);
21067 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21072 setGroupValue : function(v, suppressEvent)
21074 this.startValue = this.getValue();
21076 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21077 e.dom.checked = false;
21079 if(e.dom.value == v){
21080 e.dom.checked = true;
21084 if(suppressEvent !== true){
21085 this.fireEvent('check', this, true);
21093 validate : function()
21095 if(this.getVisibilityEl().hasClass('hidden')){
21101 (this.inputType == 'radio' && this.validateRadio()) ||
21102 (this.inputType == 'checkbox' && this.validateCheckbox())
21108 this.markInvalid();
21112 validateRadio : function()
21114 if(this.getVisibilityEl().hasClass('hidden')){
21118 if(this.allowBlank){
21124 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21125 if(!e.dom.checked){
21137 validateCheckbox : function()
21140 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21141 //return (this.getValue() == this.inputValue) ? true : false;
21144 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21152 for(var i in group){
21153 if(group[i].el.isVisible(true)){
21161 for(var i in group){
21166 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21173 * Mark this field as valid
21175 markValid : function()
21179 this.fireEvent('valid', this);
21181 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21184 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21191 if(this.inputType == 'radio'){
21192 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21193 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21194 e.findParent('.form-group', false, true).addClass(_this.validClass);
21201 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21202 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21206 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21212 for(var i in group){
21213 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21214 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21219 * Mark this field as invalid
21220 * @param {String} msg The validation message
21222 markInvalid : function(msg)
21224 if(this.allowBlank){
21230 this.fireEvent('invalid', this, msg);
21232 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21235 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21239 label.markInvalid();
21242 if(this.inputType == 'radio'){
21243 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21244 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21245 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21252 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21253 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21257 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21263 for(var i in group){
21264 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21265 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21270 clearInvalid : function()
21272 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21274 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21276 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21278 if (label && label.iconEl) {
21279 label.iconEl.removeClass(label.validClass);
21280 label.iconEl.removeClass(label.invalidClass);
21284 disable : function()
21286 if(this.inputType != 'radio'){
21287 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21294 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21295 _this.getActionEl().addClass(this.disabledClass);
21296 e.dom.disabled = true;
21300 this.disabled = true;
21301 this.fireEvent("disable", this);
21305 enable : function()
21307 if(this.inputType != 'radio'){
21308 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21315 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21316 _this.getActionEl().removeClass(this.disabledClass);
21317 e.dom.disabled = false;
21321 this.disabled = false;
21322 this.fireEvent("enable", this);
21326 setBoxLabel : function(v)
21331 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21337 Roo.apply(Roo.bootstrap.CheckBox, {
21342 * register a CheckBox Group
21343 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21345 register : function(checkbox)
21347 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21348 this.groups[checkbox.groupId] = {};
21351 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21355 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21359 * fetch a CheckBox Group based on the group ID
21360 * @param {string} the group ID
21361 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21363 get: function(groupId) {
21364 if (typeof(this.groups[groupId]) == 'undefined') {
21368 return this.groups[groupId] ;
21381 * @class Roo.bootstrap.Radio
21382 * @extends Roo.bootstrap.Component
21383 * Bootstrap Radio class
21384 * @cfg {String} boxLabel - the label associated
21385 * @cfg {String} value - the value of radio
21388 * Create a new Radio
21389 * @param {Object} config The config object
21391 Roo.bootstrap.Radio = function(config){
21392 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21396 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21402 getAutoCreate : function()
21406 cls : 'form-group radio',
21411 html : this.boxLabel
21419 initEvents : function()
21421 this.parent().register(this);
21423 this.el.on('click', this.onClick, this);
21427 onClick : function(e)
21429 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21430 this.setChecked(true);
21434 setChecked : function(state, suppressEvent)
21436 this.parent().setValue(this.value, suppressEvent);
21440 setBoxLabel : function(v)
21445 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21460 * @class Roo.bootstrap.SecurePass
21461 * @extends Roo.bootstrap.Input
21462 * Bootstrap SecurePass class
21466 * Create a new SecurePass
21467 * @param {Object} config The config object
21470 Roo.bootstrap.SecurePass = function (config) {
21471 // these go here, so the translation tool can replace them..
21473 PwdEmpty: "Please type a password, and then retype it to confirm.",
21474 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21475 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21476 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21477 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21478 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21479 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21480 TooWeak: "Your password is Too Weak."
21482 this.meterLabel = "Password strength:";
21483 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21484 this.meterClass = [
21485 "roo-password-meter-tooweak",
21486 "roo-password-meter-weak",
21487 "roo-password-meter-medium",
21488 "roo-password-meter-strong",
21489 "roo-password-meter-grey"
21494 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21497 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21499 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21501 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21502 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21503 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21504 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21505 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21506 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21507 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21517 * @cfg {String/Object} Label for the strength meter (defaults to
21518 * 'Password strength:')
21523 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21524 * ['Weak', 'Medium', 'Strong'])
21527 pwdStrengths: false,
21540 initEvents: function ()
21542 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21544 if (this.el.is('input[type=password]') && Roo.isSafari) {
21545 this.el.on('keydown', this.SafariOnKeyDown, this);
21548 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21551 onRender: function (ct, position)
21553 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21554 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21555 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21557 this.trigger.createChild({
21562 cls: 'roo-password-meter-grey col-xs-12',
21565 //width: this.meterWidth + 'px'
21569 cls: 'roo-password-meter-text'
21575 if (this.hideTrigger) {
21576 this.trigger.setDisplayed(false);
21578 this.setSize(this.width || '', this.height || '');
21581 onDestroy: function ()
21583 if (this.trigger) {
21584 this.trigger.removeAllListeners();
21585 this.trigger.remove();
21588 this.wrap.remove();
21590 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21593 checkStrength: function ()
21595 var pwd = this.inputEl().getValue();
21596 if (pwd == this._lastPwd) {
21601 if (this.ClientSideStrongPassword(pwd)) {
21603 } else if (this.ClientSideMediumPassword(pwd)) {
21605 } else if (this.ClientSideWeakPassword(pwd)) {
21611 Roo.log('strength1: ' + strength);
21613 //var pm = this.trigger.child('div/div/div').dom;
21614 var pm = this.trigger.child('div/div');
21615 pm.removeClass(this.meterClass);
21616 pm.addClass(this.meterClass[strength]);
21619 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21621 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21623 this._lastPwd = pwd;
21627 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21629 this._lastPwd = '';
21631 var pm = this.trigger.child('div/div');
21632 pm.removeClass(this.meterClass);
21633 pm.addClass('roo-password-meter-grey');
21636 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21639 this.inputEl().dom.type='password';
21642 validateValue: function (value)
21645 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21648 if (value.length == 0) {
21649 if (this.allowBlank) {
21650 this.clearInvalid();
21654 this.markInvalid(this.errors.PwdEmpty);
21655 this.errorMsg = this.errors.PwdEmpty;
21663 if ('[\x21-\x7e]*'.match(value)) {
21664 this.markInvalid(this.errors.PwdBadChar);
21665 this.errorMsg = this.errors.PwdBadChar;
21668 if (value.length < 6) {
21669 this.markInvalid(this.errors.PwdShort);
21670 this.errorMsg = this.errors.PwdShort;
21673 if (value.length > 16) {
21674 this.markInvalid(this.errors.PwdLong);
21675 this.errorMsg = this.errors.PwdLong;
21679 if (this.ClientSideStrongPassword(value)) {
21681 } else if (this.ClientSideMediumPassword(value)) {
21683 } else if (this.ClientSideWeakPassword(value)) {
21690 if (strength < 2) {
21691 //this.markInvalid(this.errors.TooWeak);
21692 this.errorMsg = this.errors.TooWeak;
21697 console.log('strength2: ' + strength);
21699 //var pm = this.trigger.child('div/div/div').dom;
21701 var pm = this.trigger.child('div/div');
21702 pm.removeClass(this.meterClass);
21703 pm.addClass(this.meterClass[strength]);
21705 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21707 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21709 this.errorMsg = '';
21713 CharacterSetChecks: function (type)
21716 this.fResult = false;
21719 isctype: function (character, type)
21722 case this.kCapitalLetter:
21723 if (character >= 'A' && character <= 'Z') {
21728 case this.kSmallLetter:
21729 if (character >= 'a' && character <= 'z') {
21735 if (character >= '0' && character <= '9') {
21740 case this.kPunctuation:
21741 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21752 IsLongEnough: function (pwd, size)
21754 return !(pwd == null || isNaN(size) || pwd.length < size);
21757 SpansEnoughCharacterSets: function (word, nb)
21759 if (!this.IsLongEnough(word, nb))
21764 var characterSetChecks = new Array(
21765 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21766 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21769 for (var index = 0; index < word.length; ++index) {
21770 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21771 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21772 characterSetChecks[nCharSet].fResult = true;
21779 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21780 if (characterSetChecks[nCharSet].fResult) {
21785 if (nCharSets < nb) {
21791 ClientSideStrongPassword: function (pwd)
21793 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21796 ClientSideMediumPassword: function (pwd)
21798 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21801 ClientSideWeakPassword: function (pwd)
21803 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21806 })//<script type="text/javascript">
21809 * Based Ext JS Library 1.1.1
21810 * Copyright(c) 2006-2007, Ext JS, LLC.
21816 * @class Roo.HtmlEditorCore
21817 * @extends Roo.Component
21818 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21820 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21823 Roo.HtmlEditorCore = function(config){
21826 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21831 * @event initialize
21832 * Fires when the editor is fully initialized (including the iframe)
21833 * @param {Roo.HtmlEditorCore} this
21838 * Fires when the editor is first receives the focus. Any insertion must wait
21839 * until after this event.
21840 * @param {Roo.HtmlEditorCore} this
21844 * @event beforesync
21845 * Fires before the textarea is updated with content from the editor iframe. Return false
21846 * to cancel the sync.
21847 * @param {Roo.HtmlEditorCore} this
21848 * @param {String} html
21852 * @event beforepush
21853 * Fires before the iframe editor is updated with content from the textarea. Return false
21854 * to cancel the push.
21855 * @param {Roo.HtmlEditorCore} this
21856 * @param {String} html
21861 * Fires when the textarea is updated with content from the editor iframe.
21862 * @param {Roo.HtmlEditorCore} this
21863 * @param {String} html
21868 * Fires when the iframe editor is updated with content from the textarea.
21869 * @param {Roo.HtmlEditorCore} this
21870 * @param {String} html
21875 * @event editorevent
21876 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21877 * @param {Roo.HtmlEditorCore} this
21883 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21885 // defaults : white / black...
21886 this.applyBlacklists();
21893 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21897 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21903 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21908 * @cfg {Number} height (in pixels)
21912 * @cfg {Number} width (in pixels)
21917 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21920 stylesheets: false,
21925 // private properties
21926 validationEvent : false,
21928 initialized : false,
21930 sourceEditMode : false,
21931 onFocus : Roo.emptyFn,
21933 hideMode:'offsets',
21937 // blacklist + whitelisted elements..
21944 * Protected method that will not generally be called directly. It
21945 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21946 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21948 getDocMarkup : function(){
21952 // inherit styels from page...??
21953 if (this.stylesheets === false) {
21955 Roo.get(document.head).select('style').each(function(node) {
21956 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21959 Roo.get(document.head).select('link').each(function(node) {
21960 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21963 } else if (!this.stylesheets.length) {
21965 st = '<style type="text/css">' +
21966 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21969 st = '<style type="text/css">' +
21974 st += '<style type="text/css">' +
21975 'IMG { cursor: pointer } ' +
21978 var cls = 'roo-htmleditor-body';
21980 if(this.bodyCls.length){
21981 cls += ' ' + this.bodyCls;
21984 return '<html><head>' + st +
21985 //<style type="text/css">' +
21986 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21988 ' </head><body class="' + cls + '"></body></html>';
21992 onRender : function(ct, position)
21995 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21996 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21999 this.el.dom.style.border = '0 none';
22000 this.el.dom.setAttribute('tabIndex', -1);
22001 this.el.addClass('x-hidden hide');
22005 if(Roo.isIE){ // fix IE 1px bogus margin
22006 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22010 this.frameId = Roo.id();
22014 var iframe = this.owner.wrap.createChild({
22016 cls: 'form-control', // bootstrap..
22018 name: this.frameId,
22019 frameBorder : 'no',
22020 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22025 this.iframe = iframe.dom;
22027 this.assignDocWin();
22029 this.doc.designMode = 'on';
22032 this.doc.write(this.getDocMarkup());
22036 var task = { // must defer to wait for browser to be ready
22038 //console.log("run task?" + this.doc.readyState);
22039 this.assignDocWin();
22040 if(this.doc.body || this.doc.readyState == 'complete'){
22042 this.doc.designMode="on";
22046 Roo.TaskMgr.stop(task);
22047 this.initEditor.defer(10, this);
22054 Roo.TaskMgr.start(task);
22059 onResize : function(w, h)
22061 Roo.log('resize: ' +w + ',' + h );
22062 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22066 if(typeof w == 'number'){
22068 this.iframe.style.width = w + 'px';
22070 if(typeof h == 'number'){
22072 this.iframe.style.height = h + 'px';
22074 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22081 * Toggles the editor between standard and source edit mode.
22082 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22084 toggleSourceEdit : function(sourceEditMode){
22086 this.sourceEditMode = sourceEditMode === true;
22088 if(this.sourceEditMode){
22090 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22093 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22094 //this.iframe.className = '';
22097 //this.setSize(this.owner.wrap.getSize());
22098 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22105 * Protected method that will not generally be called directly. If you need/want
22106 * custom HTML cleanup, this is the method you should override.
22107 * @param {String} html The HTML to be cleaned
22108 * return {String} The cleaned HTML
22110 cleanHtml : function(html){
22111 html = String(html);
22112 if(html.length > 5){
22113 if(Roo.isSafari){ // strip safari nonsense
22114 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22117 if(html == ' '){
22124 * HTML Editor -> Textarea
22125 * Protected method that will not generally be called directly. Syncs the contents
22126 * of the editor iframe with the textarea.
22128 syncValue : function(){
22129 if(this.initialized){
22130 var bd = (this.doc.body || this.doc.documentElement);
22131 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22132 var html = bd.innerHTML;
22134 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22135 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22137 html = '<div style="'+m[0]+'">' + html + '</div>';
22140 html = this.cleanHtml(html);
22141 // fix up the special chars.. normaly like back quotes in word...
22142 // however we do not want to do this with chinese..
22143 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22144 var cc = b.charCodeAt();
22146 (cc >= 0x4E00 && cc < 0xA000 ) ||
22147 (cc >= 0x3400 && cc < 0x4E00 ) ||
22148 (cc >= 0xf900 && cc < 0xfb00 )
22154 if(this.owner.fireEvent('beforesync', this, html) !== false){
22155 this.el.dom.value = html;
22156 this.owner.fireEvent('sync', this, html);
22162 * Protected method that will not generally be called directly. Pushes the value of the textarea
22163 * into the iframe editor.
22165 pushValue : function(){
22166 if(this.initialized){
22167 var v = this.el.dom.value.trim();
22169 // if(v.length < 1){
22173 if(this.owner.fireEvent('beforepush', this, v) !== false){
22174 var d = (this.doc.body || this.doc.documentElement);
22176 this.cleanUpPaste();
22177 this.el.dom.value = d.innerHTML;
22178 this.owner.fireEvent('push', this, v);
22184 deferFocus : function(){
22185 this.focus.defer(10, this);
22189 focus : function(){
22190 if(this.win && !this.sourceEditMode){
22197 assignDocWin: function()
22199 var iframe = this.iframe;
22202 this.doc = iframe.contentWindow.document;
22203 this.win = iframe.contentWindow;
22205 // if (!Roo.get(this.frameId)) {
22208 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22209 // this.win = Roo.get(this.frameId).dom.contentWindow;
22211 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22215 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22216 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22221 initEditor : function(){
22222 //console.log("INIT EDITOR");
22223 this.assignDocWin();
22227 this.doc.designMode="on";
22229 this.doc.write(this.getDocMarkup());
22232 var dbody = (this.doc.body || this.doc.documentElement);
22233 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22234 // this copies styles from the containing element into thsi one..
22235 // not sure why we need all of this..
22236 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22238 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22239 //ss['background-attachment'] = 'fixed'; // w3c
22240 dbody.bgProperties = 'fixed'; // ie
22241 //Roo.DomHelper.applyStyles(dbody, ss);
22242 Roo.EventManager.on(this.doc, {
22243 //'mousedown': this.onEditorEvent,
22244 'mouseup': this.onEditorEvent,
22245 'dblclick': this.onEditorEvent,
22246 'click': this.onEditorEvent,
22247 'keyup': this.onEditorEvent,
22252 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22254 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22255 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22257 this.initialized = true;
22259 this.owner.fireEvent('initialize', this);
22264 onDestroy : function(){
22270 //for (var i =0; i < this.toolbars.length;i++) {
22271 // // fixme - ask toolbars for heights?
22272 // this.toolbars[i].onDestroy();
22275 //this.wrap.dom.innerHTML = '';
22276 //this.wrap.remove();
22281 onFirstFocus : function(){
22283 this.assignDocWin();
22286 this.activated = true;
22289 if(Roo.isGecko){ // prevent silly gecko errors
22291 var s = this.win.getSelection();
22292 if(!s.focusNode || s.focusNode.nodeType != 3){
22293 var r = s.getRangeAt(0);
22294 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22299 this.execCmd('useCSS', true);
22300 this.execCmd('styleWithCSS', false);
22303 this.owner.fireEvent('activate', this);
22307 adjustFont: function(btn){
22308 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22309 //if(Roo.isSafari){ // safari
22312 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22313 if(Roo.isSafari){ // safari
22314 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22315 v = (v < 10) ? 10 : v;
22316 v = (v > 48) ? 48 : v;
22317 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22322 v = Math.max(1, v+adjust);
22324 this.execCmd('FontSize', v );
22327 onEditorEvent : function(e)
22329 this.owner.fireEvent('editorevent', this, e);
22330 // this.updateToolbar();
22331 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22334 insertTag : function(tg)
22336 // could be a bit smarter... -> wrap the current selected tRoo..
22337 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22339 range = this.createRange(this.getSelection());
22340 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22341 wrappingNode.appendChild(range.extractContents());
22342 range.insertNode(wrappingNode);
22349 this.execCmd("formatblock", tg);
22353 insertText : function(txt)
22357 var range = this.createRange();
22358 range.deleteContents();
22359 //alert(Sender.getAttribute('label'));
22361 range.insertNode(this.doc.createTextNode(txt));
22367 * Executes a Midas editor command on the editor document and performs necessary focus and
22368 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22369 * @param {String} cmd The Midas command
22370 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22372 relayCmd : function(cmd, value){
22374 this.execCmd(cmd, value);
22375 this.owner.fireEvent('editorevent', this);
22376 //this.updateToolbar();
22377 this.owner.deferFocus();
22381 * Executes a Midas editor command directly on the editor document.
22382 * For visual commands, you should use {@link #relayCmd} instead.
22383 * <b>This should only be called after the editor is initialized.</b>
22384 * @param {String} cmd The Midas command
22385 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22387 execCmd : function(cmd, value){
22388 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22395 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22397 * @param {String} text | dom node..
22399 insertAtCursor : function(text)
22402 if(!this.activated){
22408 var r = this.doc.selection.createRange();
22419 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22423 // from jquery ui (MIT licenced)
22425 var win = this.win;
22427 if (win.getSelection && win.getSelection().getRangeAt) {
22428 range = win.getSelection().getRangeAt(0);
22429 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22430 range.insertNode(node);
22431 } else if (win.document.selection && win.document.selection.createRange) {
22432 // no firefox support
22433 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22434 win.document.selection.createRange().pasteHTML(txt);
22436 // no firefox support
22437 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22438 this.execCmd('InsertHTML', txt);
22447 mozKeyPress : function(e){
22449 var c = e.getCharCode(), cmd;
22452 c = String.fromCharCode(c).toLowerCase();
22466 this.cleanUpPaste.defer(100, this);
22474 e.preventDefault();
22482 fixKeys : function(){ // load time branching for fastest keydown performance
22484 return function(e){
22485 var k = e.getKey(), r;
22488 r = this.doc.selection.createRange();
22491 r.pasteHTML('    ');
22498 r = this.doc.selection.createRange();
22500 var target = r.parentElement();
22501 if(!target || target.tagName.toLowerCase() != 'li'){
22503 r.pasteHTML('<br />');
22509 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22510 this.cleanUpPaste.defer(100, this);
22516 }else if(Roo.isOpera){
22517 return function(e){
22518 var k = e.getKey();
22522 this.execCmd('InsertHTML','    ');
22525 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22526 this.cleanUpPaste.defer(100, this);
22531 }else if(Roo.isSafari){
22532 return function(e){
22533 var k = e.getKey();
22537 this.execCmd('InsertText','\t');
22541 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22542 this.cleanUpPaste.defer(100, this);
22550 getAllAncestors: function()
22552 var p = this.getSelectedNode();
22555 a.push(p); // push blank onto stack..
22556 p = this.getParentElement();
22560 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22564 a.push(this.doc.body);
22568 lastSelNode : false,
22571 getSelection : function()
22573 this.assignDocWin();
22574 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22577 getSelectedNode: function()
22579 // this may only work on Gecko!!!
22581 // should we cache this!!!!
22586 var range = this.createRange(this.getSelection()).cloneRange();
22589 var parent = range.parentElement();
22591 var testRange = range.duplicate();
22592 testRange.moveToElementText(parent);
22593 if (testRange.inRange(range)) {
22596 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22599 parent = parent.parentElement;
22604 // is ancestor a text element.
22605 var ac = range.commonAncestorContainer;
22606 if (ac.nodeType == 3) {
22607 ac = ac.parentNode;
22610 var ar = ac.childNodes;
22613 var other_nodes = [];
22614 var has_other_nodes = false;
22615 for (var i=0;i<ar.length;i++) {
22616 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22619 // fullly contained node.
22621 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22626 // probably selected..
22627 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22628 other_nodes.push(ar[i]);
22632 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22637 has_other_nodes = true;
22639 if (!nodes.length && other_nodes.length) {
22640 nodes= other_nodes;
22642 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22648 createRange: function(sel)
22650 // this has strange effects when using with
22651 // top toolbar - not sure if it's a great idea.
22652 //this.editor.contentWindow.focus();
22653 if (typeof sel != "undefined") {
22655 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22657 return this.doc.createRange();
22660 return this.doc.createRange();
22663 getParentElement: function()
22666 this.assignDocWin();
22667 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22669 var range = this.createRange(sel);
22672 var p = range.commonAncestorContainer;
22673 while (p.nodeType == 3) { // text node
22684 * Range intersection.. the hard stuff...
22688 * [ -- selected range --- ]
22692 * if end is before start or hits it. fail.
22693 * if start is after end or hits it fail.
22695 * if either hits (but other is outside. - then it's not
22701 // @see http://www.thismuchiknow.co.uk/?p=64.
22702 rangeIntersectsNode : function(range, node)
22704 var nodeRange = node.ownerDocument.createRange();
22706 nodeRange.selectNode(node);
22708 nodeRange.selectNodeContents(node);
22711 var rangeStartRange = range.cloneRange();
22712 rangeStartRange.collapse(true);
22714 var rangeEndRange = range.cloneRange();
22715 rangeEndRange.collapse(false);
22717 var nodeStartRange = nodeRange.cloneRange();
22718 nodeStartRange.collapse(true);
22720 var nodeEndRange = nodeRange.cloneRange();
22721 nodeEndRange.collapse(false);
22723 return rangeStartRange.compareBoundaryPoints(
22724 Range.START_TO_START, nodeEndRange) == -1 &&
22725 rangeEndRange.compareBoundaryPoints(
22726 Range.START_TO_START, nodeStartRange) == 1;
22730 rangeCompareNode : function(range, node)
22732 var nodeRange = node.ownerDocument.createRange();
22734 nodeRange.selectNode(node);
22736 nodeRange.selectNodeContents(node);
22740 range.collapse(true);
22742 nodeRange.collapse(true);
22744 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22745 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22747 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22749 var nodeIsBefore = ss == 1;
22750 var nodeIsAfter = ee == -1;
22752 if (nodeIsBefore && nodeIsAfter) {
22755 if (!nodeIsBefore && nodeIsAfter) {
22756 return 1; //right trailed.
22759 if (nodeIsBefore && !nodeIsAfter) {
22760 return 2; // left trailed.
22766 // private? - in a new class?
22767 cleanUpPaste : function()
22769 // cleans up the whole document..
22770 Roo.log('cleanuppaste');
22772 this.cleanUpChildren(this.doc.body);
22773 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22774 if (clean != this.doc.body.innerHTML) {
22775 this.doc.body.innerHTML = clean;
22780 cleanWordChars : function(input) {// change the chars to hex code
22781 var he = Roo.HtmlEditorCore;
22783 var output = input;
22784 Roo.each(he.swapCodes, function(sw) {
22785 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22787 output = output.replace(swapper, sw[1]);
22794 cleanUpChildren : function (n)
22796 if (!n.childNodes.length) {
22799 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22800 this.cleanUpChild(n.childNodes[i]);
22807 cleanUpChild : function (node)
22810 //console.log(node);
22811 if (node.nodeName == "#text") {
22812 // clean up silly Windows -- stuff?
22815 if (node.nodeName == "#comment") {
22816 node.parentNode.removeChild(node);
22817 // clean up silly Windows -- stuff?
22820 var lcname = node.tagName.toLowerCase();
22821 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22822 // whitelist of tags..
22824 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22826 node.parentNode.removeChild(node);
22831 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22833 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22834 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22836 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22837 // remove_keep_children = true;
22840 if (remove_keep_children) {
22841 this.cleanUpChildren(node);
22842 // inserts everything just before this node...
22843 while (node.childNodes.length) {
22844 var cn = node.childNodes[0];
22845 node.removeChild(cn);
22846 node.parentNode.insertBefore(cn, node);
22848 node.parentNode.removeChild(node);
22852 if (!node.attributes || !node.attributes.length) {
22853 this.cleanUpChildren(node);
22857 function cleanAttr(n,v)
22860 if (v.match(/^\./) || v.match(/^\//)) {
22863 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22866 if (v.match(/^#/)) {
22869 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22870 node.removeAttribute(n);
22874 var cwhite = this.cwhite;
22875 var cblack = this.cblack;
22877 function cleanStyle(n,v)
22879 if (v.match(/expression/)) { //XSS?? should we even bother..
22880 node.removeAttribute(n);
22884 var parts = v.split(/;/);
22887 Roo.each(parts, function(p) {
22888 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22892 var l = p.split(':').shift().replace(/\s+/g,'');
22893 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22895 if ( cwhite.length && cblack.indexOf(l) > -1) {
22896 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22897 //node.removeAttribute(n);
22901 // only allow 'c whitelisted system attributes'
22902 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22903 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22904 //node.removeAttribute(n);
22914 if (clean.length) {
22915 node.setAttribute(n, clean.join(';'));
22917 node.removeAttribute(n);
22923 for (var i = node.attributes.length-1; i > -1 ; i--) {
22924 var a = node.attributes[i];
22927 if (a.name.toLowerCase().substr(0,2)=='on') {
22928 node.removeAttribute(a.name);
22931 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22932 node.removeAttribute(a.name);
22935 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22936 cleanAttr(a.name,a.value); // fixme..
22939 if (a.name == 'style') {
22940 cleanStyle(a.name,a.value);
22943 /// clean up MS crap..
22944 // tecnically this should be a list of valid class'es..
22947 if (a.name == 'class') {
22948 if (a.value.match(/^Mso/)) {
22949 node.className = '';
22952 if (a.value.match(/^body$/)) {
22953 node.className = '';
22964 this.cleanUpChildren(node);
22970 * Clean up MS wordisms...
22972 cleanWord : function(node)
22977 this.cleanWord(this.doc.body);
22980 if (node.nodeName == "#text") {
22981 // clean up silly Windows -- stuff?
22984 if (node.nodeName == "#comment") {
22985 node.parentNode.removeChild(node);
22986 // clean up silly Windows -- stuff?
22990 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22991 node.parentNode.removeChild(node);
22995 // remove - but keep children..
22996 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22997 while (node.childNodes.length) {
22998 var cn = node.childNodes[0];
22999 node.removeChild(cn);
23000 node.parentNode.insertBefore(cn, node);
23002 node.parentNode.removeChild(node);
23003 this.iterateChildren(node, this.cleanWord);
23007 if (node.className.length) {
23009 var cn = node.className.split(/\W+/);
23011 Roo.each(cn, function(cls) {
23012 if (cls.match(/Mso[a-zA-Z]+/)) {
23017 node.className = cna.length ? cna.join(' ') : '';
23019 node.removeAttribute("class");
23023 if (node.hasAttribute("lang")) {
23024 node.removeAttribute("lang");
23027 if (node.hasAttribute("style")) {
23029 var styles = node.getAttribute("style").split(";");
23031 Roo.each(styles, function(s) {
23032 if (!s.match(/:/)) {
23035 var kv = s.split(":");
23036 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23039 // what ever is left... we allow.
23042 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23043 if (!nstyle.length) {
23044 node.removeAttribute('style');
23047 this.iterateChildren(node, this.cleanWord);
23053 * iterateChildren of a Node, calling fn each time, using this as the scole..
23054 * @param {DomNode} node node to iterate children of.
23055 * @param {Function} fn method of this class to call on each item.
23057 iterateChildren : function(node, fn)
23059 if (!node.childNodes.length) {
23062 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23063 fn.call(this, node.childNodes[i])
23069 * cleanTableWidths.
23071 * Quite often pasting from word etc.. results in tables with column and widths.
23072 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23075 cleanTableWidths : function(node)
23080 this.cleanTableWidths(this.doc.body);
23085 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23088 Roo.log(node.tagName);
23089 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23090 this.iterateChildren(node, this.cleanTableWidths);
23093 if (node.hasAttribute('width')) {
23094 node.removeAttribute('width');
23098 if (node.hasAttribute("style")) {
23101 var styles = node.getAttribute("style").split(";");
23103 Roo.each(styles, function(s) {
23104 if (!s.match(/:/)) {
23107 var kv = s.split(":");
23108 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23111 // what ever is left... we allow.
23114 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23115 if (!nstyle.length) {
23116 node.removeAttribute('style');
23120 this.iterateChildren(node, this.cleanTableWidths);
23128 domToHTML : function(currentElement, depth, nopadtext) {
23130 depth = depth || 0;
23131 nopadtext = nopadtext || false;
23133 if (!currentElement) {
23134 return this.domToHTML(this.doc.body);
23137 //Roo.log(currentElement);
23139 var allText = false;
23140 var nodeName = currentElement.nodeName;
23141 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23143 if (nodeName == '#text') {
23145 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23150 if (nodeName != 'BODY') {
23153 // Prints the node tagName, such as <A>, <IMG>, etc
23156 for(i = 0; i < currentElement.attributes.length;i++) {
23158 var aname = currentElement.attributes.item(i).name;
23159 if (!currentElement.attributes.item(i).value.length) {
23162 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23165 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23174 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23177 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23182 // Traverse the tree
23184 var currentElementChild = currentElement.childNodes.item(i);
23185 var allText = true;
23186 var innerHTML = '';
23188 while (currentElementChild) {
23189 // Formatting code (indent the tree so it looks nice on the screen)
23190 var nopad = nopadtext;
23191 if (lastnode == 'SPAN') {
23195 if (currentElementChild.nodeName == '#text') {
23196 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23197 toadd = nopadtext ? toadd : toadd.trim();
23198 if (!nopad && toadd.length > 80) {
23199 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23201 innerHTML += toadd;
23204 currentElementChild = currentElement.childNodes.item(i);
23210 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23212 // Recursively traverse the tree structure of the child node
23213 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23214 lastnode = currentElementChild.nodeName;
23216 currentElementChild=currentElement.childNodes.item(i);
23222 // The remaining code is mostly for formatting the tree
23223 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23228 ret+= "</"+tagName+">";
23234 applyBlacklists : function()
23236 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23237 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23241 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23242 if (b.indexOf(tag) > -1) {
23245 this.white.push(tag);
23249 Roo.each(w, function(tag) {
23250 if (b.indexOf(tag) > -1) {
23253 if (this.white.indexOf(tag) > -1) {
23256 this.white.push(tag);
23261 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23262 if (w.indexOf(tag) > -1) {
23265 this.black.push(tag);
23269 Roo.each(b, function(tag) {
23270 if (w.indexOf(tag) > -1) {
23273 if (this.black.indexOf(tag) > -1) {
23276 this.black.push(tag);
23281 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23282 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23286 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23287 if (b.indexOf(tag) > -1) {
23290 this.cwhite.push(tag);
23294 Roo.each(w, function(tag) {
23295 if (b.indexOf(tag) > -1) {
23298 if (this.cwhite.indexOf(tag) > -1) {
23301 this.cwhite.push(tag);
23306 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23307 if (w.indexOf(tag) > -1) {
23310 this.cblack.push(tag);
23314 Roo.each(b, function(tag) {
23315 if (w.indexOf(tag) > -1) {
23318 if (this.cblack.indexOf(tag) > -1) {
23321 this.cblack.push(tag);
23326 setStylesheets : function(stylesheets)
23328 if(typeof(stylesheets) == 'string'){
23329 Roo.get(this.iframe.contentDocument.head).createChild({
23331 rel : 'stylesheet',
23340 Roo.each(stylesheets, function(s) {
23345 Roo.get(_this.iframe.contentDocument.head).createChild({
23347 rel : 'stylesheet',
23356 removeStylesheets : function()
23360 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23365 setStyle : function(style)
23367 Roo.get(this.iframe.contentDocument.head).createChild({
23376 // hide stuff that is not compatible
23390 * @event specialkey
23394 * @cfg {String} fieldClass @hide
23397 * @cfg {String} focusClass @hide
23400 * @cfg {String} autoCreate @hide
23403 * @cfg {String} inputType @hide
23406 * @cfg {String} invalidClass @hide
23409 * @cfg {String} invalidText @hide
23412 * @cfg {String} msgFx @hide
23415 * @cfg {String} validateOnBlur @hide
23419 Roo.HtmlEditorCore.white = [
23420 'area', 'br', 'img', 'input', 'hr', 'wbr',
23422 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23423 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23424 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23425 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23426 'table', 'ul', 'xmp',
23428 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23431 'dir', 'menu', 'ol', 'ul', 'dl',
23437 Roo.HtmlEditorCore.black = [
23438 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23440 'base', 'basefont', 'bgsound', 'blink', 'body',
23441 'frame', 'frameset', 'head', 'html', 'ilayer',
23442 'iframe', 'layer', 'link', 'meta', 'object',
23443 'script', 'style' ,'title', 'xml' // clean later..
23445 Roo.HtmlEditorCore.clean = [
23446 'script', 'style', 'title', 'xml'
23448 Roo.HtmlEditorCore.remove = [
23453 Roo.HtmlEditorCore.ablack = [
23457 Roo.HtmlEditorCore.aclean = [
23458 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23462 Roo.HtmlEditorCore.pwhite= [
23463 'http', 'https', 'mailto'
23466 // white listed style attributes.
23467 Roo.HtmlEditorCore.cwhite= [
23468 // 'text-align', /// default is to allow most things..
23474 // black listed style attributes.
23475 Roo.HtmlEditorCore.cblack= [
23476 // 'font-size' -- this can be set by the project
23480 Roo.HtmlEditorCore.swapCodes =[
23499 * @class Roo.bootstrap.HtmlEditor
23500 * @extends Roo.bootstrap.TextArea
23501 * Bootstrap HtmlEditor class
23504 * Create a new HtmlEditor
23505 * @param {Object} config The config object
23508 Roo.bootstrap.HtmlEditor = function(config){
23509 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23510 if (!this.toolbars) {
23511 this.toolbars = [];
23514 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23517 * @event initialize
23518 * Fires when the editor is fully initialized (including the iframe)
23519 * @param {HtmlEditor} this
23524 * Fires when the editor is first receives the focus. Any insertion must wait
23525 * until after this event.
23526 * @param {HtmlEditor} this
23530 * @event beforesync
23531 * Fires before the textarea is updated with content from the editor iframe. Return false
23532 * to cancel the sync.
23533 * @param {HtmlEditor} this
23534 * @param {String} html
23538 * @event beforepush
23539 * Fires before the iframe editor is updated with content from the textarea. Return false
23540 * to cancel the push.
23541 * @param {HtmlEditor} this
23542 * @param {String} html
23547 * Fires when the textarea is updated with content from the editor iframe.
23548 * @param {HtmlEditor} this
23549 * @param {String} html
23554 * Fires when the iframe editor is updated with content from the textarea.
23555 * @param {HtmlEditor} this
23556 * @param {String} html
23560 * @event editmodechange
23561 * Fires when the editor switches edit modes
23562 * @param {HtmlEditor} this
23563 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23565 editmodechange: true,
23567 * @event editorevent
23568 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23569 * @param {HtmlEditor} this
23573 * @event firstfocus
23574 * Fires when on first focus - needed by toolbars..
23575 * @param {HtmlEditor} this
23580 * Auto save the htmlEditor value as a file into Events
23581 * @param {HtmlEditor} this
23585 * @event savedpreview
23586 * preview the saved version of htmlEditor
23587 * @param {HtmlEditor} this
23594 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23598 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23603 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23608 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23613 * @cfg {Number} height (in pixels)
23617 * @cfg {Number} width (in pixels)
23622 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23625 stylesheets: false,
23630 // private properties
23631 validationEvent : false,
23633 initialized : false,
23636 onFocus : Roo.emptyFn,
23638 hideMode:'offsets',
23640 tbContainer : false,
23644 toolbarContainer :function() {
23645 return this.wrap.select('.x-html-editor-tb',true).first();
23649 * Protected method that will not generally be called directly. It
23650 * is called when the editor creates its toolbar. Override this method if you need to
23651 * add custom toolbar buttons.
23652 * @param {HtmlEditor} editor
23654 createToolbar : function(){
23655 Roo.log('renewing');
23656 Roo.log("create toolbars");
23658 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23659 this.toolbars[0].render(this.toolbarContainer());
23663 // if (!editor.toolbars || !editor.toolbars.length) {
23664 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23667 // for (var i =0 ; i < editor.toolbars.length;i++) {
23668 // editor.toolbars[i] = Roo.factory(
23669 // typeof(editor.toolbars[i]) == 'string' ?
23670 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23671 // Roo.bootstrap.HtmlEditor);
23672 // editor.toolbars[i].init(editor);
23678 onRender : function(ct, position)
23680 // Roo.log("Call onRender: " + this.xtype);
23682 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23684 this.wrap = this.inputEl().wrap({
23685 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23688 this.editorcore.onRender(ct, position);
23690 if (this.resizable) {
23691 this.resizeEl = new Roo.Resizable(this.wrap, {
23695 minHeight : this.height,
23696 height: this.height,
23697 handles : this.resizable,
23700 resize : function(r, w, h) {
23701 _t.onResize(w,h); // -something
23707 this.createToolbar(this);
23710 if(!this.width && this.resizable){
23711 this.setSize(this.wrap.getSize());
23713 if (this.resizeEl) {
23714 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23715 // should trigger onReize..
23721 onResize : function(w, h)
23723 Roo.log('resize: ' +w + ',' + h );
23724 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23728 if(this.inputEl() ){
23729 if(typeof w == 'number'){
23730 var aw = w - this.wrap.getFrameWidth('lr');
23731 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23734 if(typeof h == 'number'){
23735 var tbh = -11; // fixme it needs to tool bar size!
23736 for (var i =0; i < this.toolbars.length;i++) {
23737 // fixme - ask toolbars for heights?
23738 tbh += this.toolbars[i].el.getHeight();
23739 //if (this.toolbars[i].footer) {
23740 // tbh += this.toolbars[i].footer.el.getHeight();
23748 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23749 ah -= 5; // knock a few pixes off for look..
23750 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23754 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23755 this.editorcore.onResize(ew,eh);
23760 * Toggles the editor between standard and source edit mode.
23761 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23763 toggleSourceEdit : function(sourceEditMode)
23765 this.editorcore.toggleSourceEdit(sourceEditMode);
23767 if(this.editorcore.sourceEditMode){
23768 Roo.log('editor - showing textarea');
23771 // Roo.log(this.syncValue());
23773 this.inputEl().removeClass(['hide', 'x-hidden']);
23774 this.inputEl().dom.removeAttribute('tabIndex');
23775 this.inputEl().focus();
23777 Roo.log('editor - hiding textarea');
23779 // Roo.log(this.pushValue());
23782 this.inputEl().addClass(['hide', 'x-hidden']);
23783 this.inputEl().dom.setAttribute('tabIndex', -1);
23784 //this.deferFocus();
23787 if(this.resizable){
23788 this.setSize(this.wrap.getSize());
23791 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23794 // private (for BoxComponent)
23795 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23797 // private (for BoxComponent)
23798 getResizeEl : function(){
23802 // private (for BoxComponent)
23803 getPositionEl : function(){
23808 initEvents : function(){
23809 this.originalValue = this.getValue();
23813 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23816 // markInvalid : Roo.emptyFn,
23818 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23821 // clearInvalid : Roo.emptyFn,
23823 setValue : function(v){
23824 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23825 this.editorcore.pushValue();
23830 deferFocus : function(){
23831 this.focus.defer(10, this);
23835 focus : function(){
23836 this.editorcore.focus();
23842 onDestroy : function(){
23848 for (var i =0; i < this.toolbars.length;i++) {
23849 // fixme - ask toolbars for heights?
23850 this.toolbars[i].onDestroy();
23853 this.wrap.dom.innerHTML = '';
23854 this.wrap.remove();
23859 onFirstFocus : function(){
23860 //Roo.log("onFirstFocus");
23861 this.editorcore.onFirstFocus();
23862 for (var i =0; i < this.toolbars.length;i++) {
23863 this.toolbars[i].onFirstFocus();
23869 syncValue : function()
23871 this.editorcore.syncValue();
23874 pushValue : function()
23876 this.editorcore.pushValue();
23880 // hide stuff that is not compatible
23894 * @event specialkey
23898 * @cfg {String} fieldClass @hide
23901 * @cfg {String} focusClass @hide
23904 * @cfg {String} autoCreate @hide
23907 * @cfg {String} inputType @hide
23910 * @cfg {String} invalidClass @hide
23913 * @cfg {String} invalidText @hide
23916 * @cfg {String} msgFx @hide
23919 * @cfg {String} validateOnBlur @hide
23928 Roo.namespace('Roo.bootstrap.htmleditor');
23930 * @class Roo.bootstrap.HtmlEditorToolbar1
23935 new Roo.bootstrap.HtmlEditor({
23938 new Roo.bootstrap.HtmlEditorToolbar1({
23939 disable : { fonts: 1 , format: 1, ..., ... , ...],
23945 * @cfg {Object} disable List of elements to disable..
23946 * @cfg {Array} btns List of additional buttons.
23950 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23953 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23956 Roo.apply(this, config);
23958 // default disabled, based on 'good practice'..
23959 this.disable = this.disable || {};
23960 Roo.applyIf(this.disable, {
23963 specialElements : true
23965 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23967 this.editor = config.editor;
23968 this.editorcore = config.editor.editorcore;
23970 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23972 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23973 // dont call parent... till later.
23975 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23980 editorcore : false,
23985 "h1","h2","h3","h4","h5","h6",
23987 "abbr", "acronym", "address", "cite", "samp", "var",
23991 onRender : function(ct, position)
23993 // Roo.log("Call onRender: " + this.xtype);
23995 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23997 this.el.dom.style.marginBottom = '0';
23999 var editorcore = this.editorcore;
24000 var editor= this.editor;
24003 var btn = function(id,cmd , toggle, handler, html){
24005 var event = toggle ? 'toggle' : 'click';
24010 xns: Roo.bootstrap,
24014 enableToggle:toggle !== false,
24016 pressed : toggle ? false : null,
24019 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24020 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24026 // var cb_box = function...
24031 xns: Roo.bootstrap,
24036 xns: Roo.bootstrap,
24040 Roo.each(this.formats, function(f) {
24041 style.menu.items.push({
24043 xns: Roo.bootstrap,
24044 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24049 editorcore.insertTag(this.tagname);
24056 children.push(style);
24058 btn('bold',false,true);
24059 btn('italic',false,true);
24060 btn('align-left', 'justifyleft',true);
24061 btn('align-center', 'justifycenter',true);
24062 btn('align-right' , 'justifyright',true);
24063 btn('link', false, false, function(btn) {
24064 //Roo.log("create link?");
24065 var url = prompt(this.createLinkText, this.defaultLinkValue);
24066 if(url && url != 'http:/'+'/'){
24067 this.editorcore.relayCmd('createlink', url);
24070 btn('list','insertunorderedlist',true);
24071 btn('pencil', false,true, function(btn){
24073 this.toggleSourceEdit(btn.pressed);
24076 if (this.editor.btns.length > 0) {
24077 for (var i = 0; i<this.editor.btns.length; i++) {
24078 children.push(this.editor.btns[i]);
24086 xns: Roo.bootstrap,
24091 xns: Roo.bootstrap,
24096 cog.menu.items.push({
24098 xns: Roo.bootstrap,
24099 html : Clean styles,
24104 editorcore.insertTag(this.tagname);
24113 this.xtype = 'NavSimplebar';
24115 for(var i=0;i< children.length;i++) {
24117 this.buttons.add(this.addxtypeChild(children[i]));
24121 editor.on('editorevent', this.updateToolbar, this);
24123 onBtnClick : function(id)
24125 this.editorcore.relayCmd(id);
24126 this.editorcore.focus();
24130 * Protected method that will not generally be called directly. It triggers
24131 * a toolbar update by reading the markup state of the current selection in the editor.
24133 updateToolbar: function(){
24135 if(!this.editorcore.activated){
24136 this.editor.onFirstFocus(); // is this neeed?
24140 var btns = this.buttons;
24141 var doc = this.editorcore.doc;
24142 btns.get('bold').setActive(doc.queryCommandState('bold'));
24143 btns.get('italic').setActive(doc.queryCommandState('italic'));
24144 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24146 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24147 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24148 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24150 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24151 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24154 var ans = this.editorcore.getAllAncestors();
24155 if (this.formatCombo) {
24158 var store = this.formatCombo.store;
24159 this.formatCombo.setValue("");
24160 for (var i =0; i < ans.length;i++) {
24161 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24163 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24171 // hides menus... - so this cant be on a menu...
24172 Roo.bootstrap.MenuMgr.hideAll();
24174 Roo.bootstrap.MenuMgr.hideAll();
24175 //this.editorsyncValue();
24177 onFirstFocus: function() {
24178 this.buttons.each(function(item){
24182 toggleSourceEdit : function(sourceEditMode){
24185 if(sourceEditMode){
24186 Roo.log("disabling buttons");
24187 this.buttons.each( function(item){
24188 if(item.cmd != 'pencil'){
24194 Roo.log("enabling buttons");
24195 if(this.editorcore.initialized){
24196 this.buttons.each( function(item){
24202 Roo.log("calling toggole on editor");
24203 // tell the editor that it's been pressed..
24204 this.editor.toggleSourceEdit(sourceEditMode);
24214 * @class Roo.bootstrap.Table.AbstractSelectionModel
24215 * @extends Roo.util.Observable
24216 * Abstract base class for grid SelectionModels. It provides the interface that should be
24217 * implemented by descendant classes. This class should not be directly instantiated.
24220 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24221 this.locked = false;
24222 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24226 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24227 /** @ignore Called by the grid automatically. Do not call directly. */
24228 init : function(grid){
24234 * Locks the selections.
24237 this.locked = true;
24241 * Unlocks the selections.
24243 unlock : function(){
24244 this.locked = false;
24248 * Returns true if the selections are locked.
24249 * @return {Boolean}
24251 isLocked : function(){
24252 return this.locked;
24256 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24257 * @class Roo.bootstrap.Table.RowSelectionModel
24258 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24259 * It supports multiple selections and keyboard selection/navigation.
24261 * @param {Object} config
24264 Roo.bootstrap.Table.RowSelectionModel = function(config){
24265 Roo.apply(this, config);
24266 this.selections = new Roo.util.MixedCollection(false, function(o){
24271 this.lastActive = false;
24275 * @event selectionchange
24276 * Fires when the selection changes
24277 * @param {SelectionModel} this
24279 "selectionchange" : true,
24281 * @event afterselectionchange
24282 * Fires after the selection changes (eg. by key press or clicking)
24283 * @param {SelectionModel} this
24285 "afterselectionchange" : true,
24287 * @event beforerowselect
24288 * Fires when a row is selected being selected, return false to cancel.
24289 * @param {SelectionModel} this
24290 * @param {Number} rowIndex The selected index
24291 * @param {Boolean} keepExisting False if other selections will be cleared
24293 "beforerowselect" : true,
24296 * Fires when a row is selected.
24297 * @param {SelectionModel} this
24298 * @param {Number} rowIndex The selected index
24299 * @param {Roo.data.Record} r The record
24301 "rowselect" : true,
24303 * @event rowdeselect
24304 * Fires when a row is deselected.
24305 * @param {SelectionModel} this
24306 * @param {Number} rowIndex The selected index
24308 "rowdeselect" : true
24310 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24311 this.locked = false;
24314 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24316 * @cfg {Boolean} singleSelect
24317 * True to allow selection of only one row at a time (defaults to false)
24319 singleSelect : false,
24322 initEvents : function()
24325 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24326 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24327 //}else{ // allow click to work like normal
24328 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24330 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24331 this.grid.on("rowclick", this.handleMouseDown, this);
24333 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24334 "up" : function(e){
24336 this.selectPrevious(e.shiftKey);
24337 }else if(this.last !== false && this.lastActive !== false){
24338 var last = this.last;
24339 this.selectRange(this.last, this.lastActive-1);
24340 this.grid.getView().focusRow(this.lastActive);
24341 if(last !== false){
24345 this.selectFirstRow();
24347 this.fireEvent("afterselectionchange", this);
24349 "down" : function(e){
24351 this.selectNext(e.shiftKey);
24352 }else if(this.last !== false && this.lastActive !== false){
24353 var last = this.last;
24354 this.selectRange(this.last, this.lastActive+1);
24355 this.grid.getView().focusRow(this.lastActive);
24356 if(last !== false){
24360 this.selectFirstRow();
24362 this.fireEvent("afterselectionchange", this);
24366 this.grid.store.on('load', function(){
24367 this.selections.clear();
24370 var view = this.grid.view;
24371 view.on("refresh", this.onRefresh, this);
24372 view.on("rowupdated", this.onRowUpdated, this);
24373 view.on("rowremoved", this.onRemove, this);
24378 onRefresh : function()
24380 var ds = this.grid.store, i, v = this.grid.view;
24381 var s = this.selections;
24382 s.each(function(r){
24383 if((i = ds.indexOfId(r.id)) != -1){
24392 onRemove : function(v, index, r){
24393 this.selections.remove(r);
24397 onRowUpdated : function(v, index, r){
24398 if(this.isSelected(r)){
24399 v.onRowSelect(index);
24405 * @param {Array} records The records to select
24406 * @param {Boolean} keepExisting (optional) True to keep existing selections
24408 selectRecords : function(records, keepExisting)
24411 this.clearSelections();
24413 var ds = this.grid.store;
24414 for(var i = 0, len = records.length; i < len; i++){
24415 this.selectRow(ds.indexOf(records[i]), true);
24420 * Gets the number of selected rows.
24423 getCount : function(){
24424 return this.selections.length;
24428 * Selects the first row in the grid.
24430 selectFirstRow : function(){
24435 * Select the last row.
24436 * @param {Boolean} keepExisting (optional) True to keep existing selections
24438 selectLastRow : function(keepExisting){
24439 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24440 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24444 * Selects the row immediately following the last selected row.
24445 * @param {Boolean} keepExisting (optional) True to keep existing selections
24447 selectNext : function(keepExisting)
24449 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24450 this.selectRow(this.last+1, keepExisting);
24451 this.grid.getView().focusRow(this.last);
24456 * Selects the row that precedes the last selected row.
24457 * @param {Boolean} keepExisting (optional) True to keep existing selections
24459 selectPrevious : function(keepExisting){
24461 this.selectRow(this.last-1, keepExisting);
24462 this.grid.getView().focusRow(this.last);
24467 * Returns the selected records
24468 * @return {Array} Array of selected records
24470 getSelections : function(){
24471 return [].concat(this.selections.items);
24475 * Returns the first selected record.
24478 getSelected : function(){
24479 return this.selections.itemAt(0);
24484 * Clears all selections.
24486 clearSelections : function(fast)
24492 var ds = this.grid.store;
24493 var s = this.selections;
24494 s.each(function(r){
24495 this.deselectRow(ds.indexOfId(r.id));
24499 this.selections.clear();
24506 * Selects all rows.
24508 selectAll : function(){
24512 this.selections.clear();
24513 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24514 this.selectRow(i, true);
24519 * Returns True if there is a selection.
24520 * @return {Boolean}
24522 hasSelection : function(){
24523 return this.selections.length > 0;
24527 * Returns True if the specified row is selected.
24528 * @param {Number/Record} record The record or index of the record to check
24529 * @return {Boolean}
24531 isSelected : function(index){
24532 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24533 return (r && this.selections.key(r.id) ? true : false);
24537 * Returns True if the specified record id is selected.
24538 * @param {String} id The id of record to check
24539 * @return {Boolean}
24541 isIdSelected : function(id){
24542 return (this.selections.key(id) ? true : false);
24547 handleMouseDBClick : function(e, t){
24551 handleMouseDown : function(e, t)
24553 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24554 if(this.isLocked() || rowIndex < 0 ){
24557 if(e.shiftKey && this.last !== false){
24558 var last = this.last;
24559 this.selectRange(last, rowIndex, e.ctrlKey);
24560 this.last = last; // reset the last
24564 var isSelected = this.isSelected(rowIndex);
24565 //Roo.log("select row:" + rowIndex);
24567 this.deselectRow(rowIndex);
24569 this.selectRow(rowIndex, true);
24573 if(e.button !== 0 && isSelected){
24574 alert('rowIndex 2: ' + rowIndex);
24575 view.focusRow(rowIndex);
24576 }else if(e.ctrlKey && isSelected){
24577 this.deselectRow(rowIndex);
24578 }else if(!isSelected){
24579 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24580 view.focusRow(rowIndex);
24584 this.fireEvent("afterselectionchange", this);
24587 handleDragableRowClick : function(grid, rowIndex, e)
24589 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24590 this.selectRow(rowIndex, false);
24591 grid.view.focusRow(rowIndex);
24592 this.fireEvent("afterselectionchange", this);
24597 * Selects multiple rows.
24598 * @param {Array} rows Array of the indexes of the row to select
24599 * @param {Boolean} keepExisting (optional) True to keep existing selections
24601 selectRows : function(rows, keepExisting){
24603 this.clearSelections();
24605 for(var i = 0, len = rows.length; i < len; i++){
24606 this.selectRow(rows[i], true);
24611 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24612 * @param {Number} startRow The index of the first row in the range
24613 * @param {Number} endRow The index of the last row in the range
24614 * @param {Boolean} keepExisting (optional) True to retain existing selections
24616 selectRange : function(startRow, endRow, keepExisting){
24621 this.clearSelections();
24623 if(startRow <= endRow){
24624 for(var i = startRow; i <= endRow; i++){
24625 this.selectRow(i, true);
24628 for(var i = startRow; i >= endRow; i--){
24629 this.selectRow(i, true);
24635 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24636 * @param {Number} startRow The index of the first row in the range
24637 * @param {Number} endRow The index of the last row in the range
24639 deselectRange : function(startRow, endRow, preventViewNotify){
24643 for(var i = startRow; i <= endRow; i++){
24644 this.deselectRow(i, preventViewNotify);
24650 * @param {Number} row The index of the row to select
24651 * @param {Boolean} keepExisting (optional) True to keep existing selections
24653 selectRow : function(index, keepExisting, preventViewNotify)
24655 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24658 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24659 if(!keepExisting || this.singleSelect){
24660 this.clearSelections();
24663 var r = this.grid.store.getAt(index);
24664 //console.log('selectRow - record id :' + r.id);
24666 this.selections.add(r);
24667 this.last = this.lastActive = index;
24668 if(!preventViewNotify){
24669 var proxy = new Roo.Element(
24670 this.grid.getRowDom(index)
24672 proxy.addClass('bg-info info');
24674 this.fireEvent("rowselect", this, index, r);
24675 this.fireEvent("selectionchange", this);
24681 * @param {Number} row The index of the row to deselect
24683 deselectRow : function(index, preventViewNotify)
24688 if(this.last == index){
24691 if(this.lastActive == index){
24692 this.lastActive = false;
24695 var r = this.grid.store.getAt(index);
24700 this.selections.remove(r);
24701 //.console.log('deselectRow - record id :' + r.id);
24702 if(!preventViewNotify){
24704 var proxy = new Roo.Element(
24705 this.grid.getRowDom(index)
24707 proxy.removeClass('bg-info info');
24709 this.fireEvent("rowdeselect", this, index);
24710 this.fireEvent("selectionchange", this);
24714 restoreLast : function(){
24716 this.last = this._last;
24721 acceptsNav : function(row, col, cm){
24722 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24726 onEditorKey : function(field, e){
24727 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24732 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24734 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24736 }else if(k == e.ENTER && !e.ctrlKey){
24740 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24742 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24744 }else if(k == e.ESC){
24748 g.startEditing(newCell[0], newCell[1]);
24754 * Ext JS Library 1.1.1
24755 * Copyright(c) 2006-2007, Ext JS, LLC.
24757 * Originally Released Under LGPL - original licence link has changed is not relivant.
24760 * <script type="text/javascript">
24764 * @class Roo.bootstrap.PagingToolbar
24765 * @extends Roo.bootstrap.NavSimplebar
24766 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24768 * Create a new PagingToolbar
24769 * @param {Object} config The config object
24770 * @param {Roo.data.Store} store
24772 Roo.bootstrap.PagingToolbar = function(config)
24774 // old args format still supported... - xtype is prefered..
24775 // created from xtype...
24777 this.ds = config.dataSource;
24779 if (config.store && !this.ds) {
24780 this.store= Roo.factory(config.store, Roo.data);
24781 this.ds = this.store;
24782 this.ds.xmodule = this.xmodule || false;
24785 this.toolbarItems = [];
24786 if (config.items) {
24787 this.toolbarItems = config.items;
24790 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24795 this.bind(this.ds);
24798 if (Roo.bootstrap.version == 4) {
24799 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24801 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24806 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24808 * @cfg {Roo.data.Store} dataSource
24809 * The underlying data store providing the paged data
24812 * @cfg {String/HTMLElement/Element} container
24813 * container The id or element that will contain the toolbar
24816 * @cfg {Boolean} displayInfo
24817 * True to display the displayMsg (defaults to false)
24820 * @cfg {Number} pageSize
24821 * The number of records to display per page (defaults to 20)
24825 * @cfg {String} displayMsg
24826 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24828 displayMsg : 'Displaying {0} - {1} of {2}',
24830 * @cfg {String} emptyMsg
24831 * The message to display when no records are found (defaults to "No data to display")
24833 emptyMsg : 'No data to display',
24835 * Customizable piece of the default paging text (defaults to "Page")
24838 beforePageText : "Page",
24840 * Customizable piece of the default paging text (defaults to "of %0")
24843 afterPageText : "of {0}",
24845 * Customizable piece of the default paging text (defaults to "First Page")
24848 firstText : "First Page",
24850 * Customizable piece of the default paging text (defaults to "Previous Page")
24853 prevText : "Previous Page",
24855 * Customizable piece of the default paging text (defaults to "Next Page")
24858 nextText : "Next Page",
24860 * Customizable piece of the default paging text (defaults to "Last Page")
24863 lastText : "Last Page",
24865 * Customizable piece of the default paging text (defaults to "Refresh")
24868 refreshText : "Refresh",
24872 onRender : function(ct, position)
24874 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24875 this.navgroup.parentId = this.id;
24876 this.navgroup.onRender(this.el, null);
24877 // add the buttons to the navgroup
24879 if(this.displayInfo){
24880 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24881 this.displayEl = this.el.select('.x-paging-info', true).first();
24882 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24883 // this.displayEl = navel.el.select('span',true).first();
24889 Roo.each(_this.buttons, function(e){ // this might need to use render????
24890 Roo.factory(e).render(_this.el);
24894 Roo.each(_this.toolbarItems, function(e) {
24895 _this.navgroup.addItem(e);
24899 this.first = this.navgroup.addItem({
24900 tooltip: this.firstText,
24901 cls: "prev btn-outline-secondary",
24902 html : ' <i class="fa fa-step-backward"></i>',
24904 preventDefault: true,
24905 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24908 this.prev = this.navgroup.addItem({
24909 tooltip: this.prevText,
24910 cls: "prev btn-outline-secondary",
24911 html : ' <i class="fa fa-backward"></i>',
24913 preventDefault: true,
24914 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24916 //this.addSeparator();
24919 var field = this.navgroup.addItem( {
24921 cls : 'x-paging-position btn-outline-secondary',
24923 html : this.beforePageText +
24924 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24925 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24928 this.field = field.el.select('input', true).first();
24929 this.field.on("keydown", this.onPagingKeydown, this);
24930 this.field.on("focus", function(){this.dom.select();});
24933 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24934 //this.field.setHeight(18);
24935 //this.addSeparator();
24936 this.next = this.navgroup.addItem({
24937 tooltip: this.nextText,
24938 cls: "next btn-outline-secondary",
24939 html : ' <i class="fa fa-forward"></i>',
24941 preventDefault: true,
24942 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24944 this.last = this.navgroup.addItem({
24945 tooltip: this.lastText,
24946 html : ' <i class="fa fa-step-forward"></i>',
24947 cls: "next btn-outline-secondary",
24949 preventDefault: true,
24950 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24952 //this.addSeparator();
24953 this.loading = this.navgroup.addItem({
24954 tooltip: this.refreshText,
24955 cls: "btn-outline-secondary",
24956 html : ' <i class="fa fa-refresh"></i>',
24957 preventDefault: true,
24958 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24964 updateInfo : function(){
24965 if(this.displayEl){
24966 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24967 var msg = count == 0 ?
24971 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24973 this.displayEl.update(msg);
24978 onLoad : function(ds, r, o)
24980 this.cursor = o.params.start ? o.params.start : 0;
24982 var d = this.getPageData(),
24987 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24988 this.field.dom.value = ap;
24989 this.first.setDisabled(ap == 1);
24990 this.prev.setDisabled(ap == 1);
24991 this.next.setDisabled(ap == ps);
24992 this.last.setDisabled(ap == ps);
24993 this.loading.enable();
24998 getPageData : function(){
24999 var total = this.ds.getTotalCount();
25002 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25003 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25008 onLoadError : function(){
25009 this.loading.enable();
25013 onPagingKeydown : function(e){
25014 var k = e.getKey();
25015 var d = this.getPageData();
25017 var v = this.field.dom.value, pageNum;
25018 if(!v || isNaN(pageNum = parseInt(v, 10))){
25019 this.field.dom.value = d.activePage;
25022 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25023 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25026 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))
25028 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25029 this.field.dom.value = pageNum;
25030 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25033 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25035 var v = this.field.dom.value, pageNum;
25036 var increment = (e.shiftKey) ? 10 : 1;
25037 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25040 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25041 this.field.dom.value = d.activePage;
25044 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25046 this.field.dom.value = parseInt(v, 10) + increment;
25047 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25048 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25055 beforeLoad : function(){
25057 this.loading.disable();
25062 onClick : function(which){
25071 ds.load({params:{start: 0, limit: this.pageSize}});
25074 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25077 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25080 var total = ds.getTotalCount();
25081 var extra = total % this.pageSize;
25082 var lastStart = extra ? (total - extra) : total-this.pageSize;
25083 ds.load({params:{start: lastStart, limit: this.pageSize}});
25086 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25092 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25093 * @param {Roo.data.Store} store The data store to unbind
25095 unbind : function(ds){
25096 ds.un("beforeload", this.beforeLoad, this);
25097 ds.un("load", this.onLoad, this);
25098 ds.un("loadexception", this.onLoadError, this);
25099 ds.un("remove", this.updateInfo, this);
25100 ds.un("add", this.updateInfo, this);
25101 this.ds = undefined;
25105 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25106 * @param {Roo.data.Store} store The data store to bind
25108 bind : function(ds){
25109 ds.on("beforeload", this.beforeLoad, this);
25110 ds.on("load", this.onLoad, this);
25111 ds.on("loadexception", this.onLoadError, this);
25112 ds.on("remove", this.updateInfo, this);
25113 ds.on("add", this.updateInfo, this);
25124 * @class Roo.bootstrap.MessageBar
25125 * @extends Roo.bootstrap.Component
25126 * Bootstrap MessageBar class
25127 * @cfg {String} html contents of the MessageBar
25128 * @cfg {String} weight (info | success | warning | danger) default info
25129 * @cfg {String} beforeClass insert the bar before the given class
25130 * @cfg {Boolean} closable (true | false) default false
25131 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25134 * Create a new Element
25135 * @param {Object} config The config object
25138 Roo.bootstrap.MessageBar = function(config){
25139 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25142 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25148 beforeClass: 'bootstrap-sticky-wrap',
25150 getAutoCreate : function(){
25154 cls: 'alert alert-dismissable alert-' + this.weight,
25159 html: this.html || ''
25165 cfg.cls += ' alert-messages-fixed';
25179 onRender : function(ct, position)
25181 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25184 var cfg = Roo.apply({}, this.getAutoCreate());
25188 cfg.cls += ' ' + this.cls;
25191 cfg.style = this.style;
25193 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25195 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25198 this.el.select('>button.close').on('click', this.hide, this);
25204 if (!this.rendered) {
25210 this.fireEvent('show', this);
25216 if (!this.rendered) {
25222 this.fireEvent('hide', this);
25225 update : function()
25227 // var e = this.el.dom.firstChild;
25229 // if(this.closable){
25230 // e = e.nextSibling;
25233 // e.data = this.html || '';
25235 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25251 * @class Roo.bootstrap.Graph
25252 * @extends Roo.bootstrap.Component
25253 * Bootstrap Graph class
25257 @cfg {String} graphtype bar | vbar | pie
25258 @cfg {number} g_x coodinator | centre x (pie)
25259 @cfg {number} g_y coodinator | centre y (pie)
25260 @cfg {number} g_r radius (pie)
25261 @cfg {number} g_height height of the chart (respected by all elements in the set)
25262 @cfg {number} g_width width of the chart (respected by all elements in the set)
25263 @cfg {Object} title The title of the chart
25266 -opts (object) options for the chart
25268 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25269 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25271 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.
25272 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25274 o stretch (boolean)
25276 -opts (object) options for the pie
25279 o startAngle (number)
25280 o endAngle (number)
25284 * Create a new Input
25285 * @param {Object} config The config object
25288 Roo.bootstrap.Graph = function(config){
25289 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25295 * The img click event for the img.
25296 * @param {Roo.EventObject} e
25302 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25313 //g_colors: this.colors,
25320 getAutoCreate : function(){
25331 onRender : function(ct,position){
25334 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25336 if (typeof(Raphael) == 'undefined') {
25337 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25341 this.raphael = Raphael(this.el.dom);
25343 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25344 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25345 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25346 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25348 r.text(160, 10, "Single Series Chart").attr(txtattr);
25349 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25350 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25351 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25353 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25354 r.barchart(330, 10, 300, 220, data1);
25355 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25356 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25359 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25360 // r.barchart(30, 30, 560, 250, xdata, {
25361 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25362 // axis : "0 0 1 1",
25363 // axisxlabels : xdata
25364 // //yvalues : cols,
25367 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25369 // this.load(null,xdata,{
25370 // axis : "0 0 1 1",
25371 // axisxlabels : xdata
25376 load : function(graphtype,xdata,opts)
25378 this.raphael.clear();
25380 graphtype = this.graphtype;
25385 var r = this.raphael,
25386 fin = function () {
25387 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25389 fout = function () {
25390 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25392 pfin = function() {
25393 this.sector.stop();
25394 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25397 this.label[0].stop();
25398 this.label[0].attr({ r: 7.5 });
25399 this.label[1].attr({ "font-weight": 800 });
25402 pfout = function() {
25403 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25406 this.label[0].animate({ r: 5 }, 500, "bounce");
25407 this.label[1].attr({ "font-weight": 400 });
25413 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25416 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25419 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25420 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25422 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25429 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25434 setTitle: function(o)
25439 initEvents: function() {
25442 this.el.on('click', this.onClick, this);
25446 onClick : function(e)
25448 Roo.log('img onclick');
25449 this.fireEvent('click', this, e);
25461 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25464 * @class Roo.bootstrap.dash.NumberBox
25465 * @extends Roo.bootstrap.Component
25466 * Bootstrap NumberBox class
25467 * @cfg {String} headline Box headline
25468 * @cfg {String} content Box content
25469 * @cfg {String} icon Box icon
25470 * @cfg {String} footer Footer text
25471 * @cfg {String} fhref Footer href
25474 * Create a new NumberBox
25475 * @param {Object} config The config object
25479 Roo.bootstrap.dash.NumberBox = function(config){
25480 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25484 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25493 getAutoCreate : function(){
25497 cls : 'small-box ',
25505 cls : 'roo-headline',
25506 html : this.headline
25510 cls : 'roo-content',
25511 html : this.content
25525 cls : 'ion ' + this.icon
25534 cls : 'small-box-footer',
25535 href : this.fhref || '#',
25539 cfg.cn.push(footer);
25546 onRender : function(ct,position){
25547 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25554 setHeadline: function (value)
25556 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25559 setFooter: function (value, href)
25561 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25564 this.el.select('a.small-box-footer',true).first().attr('href', href);
25569 setContent: function (value)
25571 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25574 initEvents: function()
25588 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25591 * @class Roo.bootstrap.dash.TabBox
25592 * @extends Roo.bootstrap.Component
25593 * Bootstrap TabBox class
25594 * @cfg {String} title Title of the TabBox
25595 * @cfg {String} icon Icon of the TabBox
25596 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25597 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25600 * Create a new TabBox
25601 * @param {Object} config The config object
25605 Roo.bootstrap.dash.TabBox = function(config){
25606 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25611 * When a pane is added
25612 * @param {Roo.bootstrap.dash.TabPane} pane
25616 * @event activatepane
25617 * When a pane is activated
25618 * @param {Roo.bootstrap.dash.TabPane} pane
25620 "activatepane" : true
25628 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25633 tabScrollable : false,
25635 getChildContainer : function()
25637 return this.el.select('.tab-content', true).first();
25640 getAutoCreate : function(){
25644 cls: 'pull-left header',
25652 cls: 'fa ' + this.icon
25658 cls: 'nav nav-tabs pull-right',
25664 if(this.tabScrollable){
25671 cls: 'nav nav-tabs pull-right',
25682 cls: 'nav-tabs-custom',
25687 cls: 'tab-content no-padding',
25695 initEvents : function()
25697 //Roo.log('add add pane handler');
25698 this.on('addpane', this.onAddPane, this);
25701 * Updates the box title
25702 * @param {String} html to set the title to.
25704 setTitle : function(value)
25706 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25708 onAddPane : function(pane)
25710 this.panes.push(pane);
25711 //Roo.log('addpane');
25713 // tabs are rendere left to right..
25714 if(!this.showtabs){
25718 var ctr = this.el.select('.nav-tabs', true).first();
25721 var existing = ctr.select('.nav-tab',true);
25722 var qty = existing.getCount();;
25725 var tab = ctr.createChild({
25727 cls : 'nav-tab' + (qty ? '' : ' active'),
25735 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25738 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25740 pane.el.addClass('active');
25745 onTabClick : function(ev,un,ob,pane)
25747 //Roo.log('tab - prev default');
25748 ev.preventDefault();
25751 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25752 pane.tab.addClass('active');
25753 //Roo.log(pane.title);
25754 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25755 // technically we should have a deactivate event.. but maybe add later.
25756 // and it should not de-activate the selected tab...
25757 this.fireEvent('activatepane', pane);
25758 pane.el.addClass('active');
25759 pane.fireEvent('activate');
25764 getActivePane : function()
25767 Roo.each(this.panes, function(p) {
25768 if(p.el.hasClass('active')){
25789 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25791 * @class Roo.bootstrap.TabPane
25792 * @extends Roo.bootstrap.Component
25793 * Bootstrap TabPane class
25794 * @cfg {Boolean} active (false | true) Default false
25795 * @cfg {String} title title of panel
25799 * Create a new TabPane
25800 * @param {Object} config The config object
25803 Roo.bootstrap.dash.TabPane = function(config){
25804 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25810 * When a pane is activated
25811 * @param {Roo.bootstrap.dash.TabPane} pane
25818 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25823 // the tabBox that this is attached to.
25826 getAutoCreate : function()
25834 cfg.cls += ' active';
25839 initEvents : function()
25841 //Roo.log('trigger add pane handler');
25842 this.parent().fireEvent('addpane', this)
25846 * Updates the tab title
25847 * @param {String} html to set the title to.
25849 setTitle: function(str)
25855 this.tab.select('a', true).first().dom.innerHTML = str;
25872 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25875 * @class Roo.bootstrap.menu.Menu
25876 * @extends Roo.bootstrap.Component
25877 * Bootstrap Menu class - container for Menu
25878 * @cfg {String} html Text of the menu
25879 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25880 * @cfg {String} icon Font awesome icon
25881 * @cfg {String} pos Menu align to (top | bottom) default bottom
25885 * Create a new Menu
25886 * @param {Object} config The config object
25890 Roo.bootstrap.menu.Menu = function(config){
25891 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25895 * @event beforeshow
25896 * Fires before this menu is displayed
25897 * @param {Roo.bootstrap.menu.Menu} this
25901 * @event beforehide
25902 * Fires before this menu is hidden
25903 * @param {Roo.bootstrap.menu.Menu} this
25908 * Fires after this menu is displayed
25909 * @param {Roo.bootstrap.menu.Menu} this
25914 * Fires after this menu is hidden
25915 * @param {Roo.bootstrap.menu.Menu} this
25920 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25921 * @param {Roo.bootstrap.menu.Menu} this
25922 * @param {Roo.EventObject} e
25929 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25933 weight : 'default',
25938 getChildContainer : function() {
25939 if(this.isSubMenu){
25943 return this.el.select('ul.dropdown-menu', true).first();
25946 getAutoCreate : function()
25951 cls : 'roo-menu-text',
25959 cls : 'fa ' + this.icon
25970 cls : 'dropdown-button btn btn-' + this.weight,
25975 cls : 'dropdown-toggle btn btn-' + this.weight,
25985 cls : 'dropdown-menu'
25991 if(this.pos == 'top'){
25992 cfg.cls += ' dropup';
25995 if(this.isSubMenu){
25998 cls : 'dropdown-menu'
26005 onRender : function(ct, position)
26007 this.isSubMenu = ct.hasClass('dropdown-submenu');
26009 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26012 initEvents : function()
26014 if(this.isSubMenu){
26018 this.hidden = true;
26020 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26021 this.triggerEl.on('click', this.onTriggerPress, this);
26023 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26024 this.buttonEl.on('click', this.onClick, this);
26030 if(this.isSubMenu){
26034 return this.el.select('ul.dropdown-menu', true).first();
26037 onClick : function(e)
26039 this.fireEvent("click", this, e);
26042 onTriggerPress : function(e)
26044 if (this.isVisible()) {
26051 isVisible : function(){
26052 return !this.hidden;
26057 this.fireEvent("beforeshow", this);
26059 this.hidden = false;
26060 this.el.addClass('open');
26062 Roo.get(document).on("mouseup", this.onMouseUp, this);
26064 this.fireEvent("show", this);
26071 this.fireEvent("beforehide", this);
26073 this.hidden = true;
26074 this.el.removeClass('open');
26076 Roo.get(document).un("mouseup", this.onMouseUp);
26078 this.fireEvent("hide", this);
26081 onMouseUp : function()
26095 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26098 * @class Roo.bootstrap.menu.Item
26099 * @extends Roo.bootstrap.Component
26100 * Bootstrap MenuItem class
26101 * @cfg {Boolean} submenu (true | false) default false
26102 * @cfg {String} html text of the item
26103 * @cfg {String} href the link
26104 * @cfg {Boolean} disable (true | false) default false
26105 * @cfg {Boolean} preventDefault (true | false) default true
26106 * @cfg {String} icon Font awesome icon
26107 * @cfg {String} pos Submenu align to (left | right) default right
26111 * Create a new Item
26112 * @param {Object} config The config object
26116 Roo.bootstrap.menu.Item = function(config){
26117 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26121 * Fires when the mouse is hovering over this menu
26122 * @param {Roo.bootstrap.menu.Item} this
26123 * @param {Roo.EventObject} e
26128 * Fires when the mouse exits this menu
26129 * @param {Roo.bootstrap.menu.Item} this
26130 * @param {Roo.EventObject} e
26136 * The raw click event for the entire grid.
26137 * @param {Roo.EventObject} e
26143 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26148 preventDefault: true,
26153 getAutoCreate : function()
26158 cls : 'roo-menu-item-text',
26166 cls : 'fa ' + this.icon
26175 href : this.href || '#',
26182 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26186 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26188 if(this.pos == 'left'){
26189 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26196 initEvents : function()
26198 this.el.on('mouseover', this.onMouseOver, this);
26199 this.el.on('mouseout', this.onMouseOut, this);
26201 this.el.select('a', true).first().on('click', this.onClick, this);
26205 onClick : function(e)
26207 if(this.preventDefault){
26208 e.preventDefault();
26211 this.fireEvent("click", this, e);
26214 onMouseOver : function(e)
26216 if(this.submenu && this.pos == 'left'){
26217 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26220 this.fireEvent("mouseover", this, e);
26223 onMouseOut : function(e)
26225 this.fireEvent("mouseout", this, e);
26237 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26240 * @class Roo.bootstrap.menu.Separator
26241 * @extends Roo.bootstrap.Component
26242 * Bootstrap Separator class
26245 * Create a new Separator
26246 * @param {Object} config The config object
26250 Roo.bootstrap.menu.Separator = function(config){
26251 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26254 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26256 getAutoCreate : function(){
26277 * @class Roo.bootstrap.Tooltip
26278 * Bootstrap Tooltip class
26279 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26280 * to determine which dom element triggers the tooltip.
26282 * It needs to add support for additional attributes like tooltip-position
26285 * Create a new Toolti
26286 * @param {Object} config The config object
26289 Roo.bootstrap.Tooltip = function(config){
26290 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26292 this.alignment = Roo.bootstrap.Tooltip.alignment;
26294 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26295 this.alignment = config.alignment;
26300 Roo.apply(Roo.bootstrap.Tooltip, {
26302 * @function init initialize tooltip monitoring.
26306 currentTip : false,
26307 currentRegion : false,
26313 Roo.get(document).on('mouseover', this.enter ,this);
26314 Roo.get(document).on('mouseout', this.leave, this);
26317 this.currentTip = new Roo.bootstrap.Tooltip();
26320 enter : function(ev)
26322 var dom = ev.getTarget();
26324 //Roo.log(['enter',dom]);
26325 var el = Roo.fly(dom);
26326 if (this.currentEl) {
26328 //Roo.log(this.currentEl);
26329 //Roo.log(this.currentEl.contains(dom));
26330 if (this.currentEl == el) {
26333 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26339 if (this.currentTip.el) {
26340 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26344 if(!el || el.dom == document){
26350 // you can not look for children, as if el is the body.. then everythign is the child..
26351 if (!el.attr('tooltip')) { //
26352 if (!el.select("[tooltip]").elements.length) {
26355 // is the mouse over this child...?
26356 bindEl = el.select("[tooltip]").first();
26357 var xy = ev.getXY();
26358 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26359 //Roo.log("not in region.");
26362 //Roo.log("child element over..");
26365 this.currentEl = bindEl;
26366 this.currentTip.bind(bindEl);
26367 this.currentRegion = Roo.lib.Region.getRegion(dom);
26368 this.currentTip.enter();
26371 leave : function(ev)
26373 var dom = ev.getTarget();
26374 //Roo.log(['leave',dom]);
26375 if (!this.currentEl) {
26380 if (dom != this.currentEl.dom) {
26383 var xy = ev.getXY();
26384 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26387 // only activate leave if mouse cursor is outside... bounding box..
26392 if (this.currentTip) {
26393 this.currentTip.leave();
26395 //Roo.log('clear currentEl');
26396 this.currentEl = false;
26401 'left' : ['r-l', [-2,0], 'right'],
26402 'right' : ['l-r', [2,0], 'left'],
26403 'bottom' : ['t-b', [0,2], 'top'],
26404 'top' : [ 'b-t', [0,-2], 'bottom']
26410 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26415 delay : null, // can be { show : 300 , hide: 500}
26419 hoverState : null, //???
26421 placement : 'bottom',
26425 getAutoCreate : function(){
26432 cls : 'tooltip-arrow'
26435 cls : 'tooltip-inner'
26442 bind : function(el)
26448 enter : function () {
26450 if (this.timeout != null) {
26451 clearTimeout(this.timeout);
26454 this.hoverState = 'in';
26455 //Roo.log("enter - show");
26456 if (!this.delay || !this.delay.show) {
26461 this.timeout = setTimeout(function () {
26462 if (_t.hoverState == 'in') {
26465 }, this.delay.show);
26469 clearTimeout(this.timeout);
26471 this.hoverState = 'out';
26472 if (!this.delay || !this.delay.hide) {
26478 this.timeout = setTimeout(function () {
26479 //Roo.log("leave - timeout");
26481 if (_t.hoverState == 'out') {
26483 Roo.bootstrap.Tooltip.currentEl = false;
26488 show : function (msg)
26491 this.render(document.body);
26494 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26496 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26498 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26500 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26502 var placement = typeof this.placement == 'function' ?
26503 this.placement.call(this, this.el, on_el) :
26506 var autoToken = /\s?auto?\s?/i;
26507 var autoPlace = autoToken.test(placement);
26509 placement = placement.replace(autoToken, '') || 'top';
26513 //this.el.setXY([0,0]);
26515 //this.el.dom.style.display='block';
26517 //this.el.appendTo(on_el);
26519 var p = this.getPosition();
26520 var box = this.el.getBox();
26526 var align = this.alignment[placement];
26528 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26530 if(placement == 'top' || placement == 'bottom'){
26532 placement = 'right';
26535 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26536 placement = 'left';
26539 var scroll = Roo.select('body', true).first().getScroll();
26541 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26545 align = this.alignment[placement];
26548 this.el.alignTo(this.bindEl, align[0],align[1]);
26549 //var arrow = this.el.select('.arrow',true).first();
26550 //arrow.set(align[2],
26552 this.el.addClass(placement);
26554 this.el.addClass('in fade');
26556 this.hoverState = null;
26558 if (this.el.hasClass('fade')) {
26569 //this.el.setXY([0,0]);
26570 this.el.removeClass('in');
26586 * @class Roo.bootstrap.LocationPicker
26587 * @extends Roo.bootstrap.Component
26588 * Bootstrap LocationPicker class
26589 * @cfg {Number} latitude Position when init default 0
26590 * @cfg {Number} longitude Position when init default 0
26591 * @cfg {Number} zoom default 15
26592 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26593 * @cfg {Boolean} mapTypeControl default false
26594 * @cfg {Boolean} disableDoubleClickZoom default false
26595 * @cfg {Boolean} scrollwheel default true
26596 * @cfg {Boolean} streetViewControl default false
26597 * @cfg {Number} radius default 0
26598 * @cfg {String} locationName
26599 * @cfg {Boolean} draggable default true
26600 * @cfg {Boolean} enableAutocomplete default false
26601 * @cfg {Boolean} enableReverseGeocode default true
26602 * @cfg {String} markerTitle
26605 * Create a new LocationPicker
26606 * @param {Object} config The config object
26610 Roo.bootstrap.LocationPicker = function(config){
26612 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26617 * Fires when the picker initialized.
26618 * @param {Roo.bootstrap.LocationPicker} this
26619 * @param {Google Location} location
26623 * @event positionchanged
26624 * Fires when the picker position changed.
26625 * @param {Roo.bootstrap.LocationPicker} this
26626 * @param {Google Location} location
26628 positionchanged : true,
26631 * Fires when the map resize.
26632 * @param {Roo.bootstrap.LocationPicker} this
26637 * Fires when the map show.
26638 * @param {Roo.bootstrap.LocationPicker} this
26643 * Fires when the map hide.
26644 * @param {Roo.bootstrap.LocationPicker} this
26649 * Fires when click the map.
26650 * @param {Roo.bootstrap.LocationPicker} this
26651 * @param {Map event} e
26655 * @event mapRightClick
26656 * Fires when right click the map.
26657 * @param {Roo.bootstrap.LocationPicker} this
26658 * @param {Map event} e
26660 mapRightClick : true,
26662 * @event markerClick
26663 * Fires when click the marker.
26664 * @param {Roo.bootstrap.LocationPicker} this
26665 * @param {Map event} e
26667 markerClick : true,
26669 * @event markerRightClick
26670 * Fires when right click the marker.
26671 * @param {Roo.bootstrap.LocationPicker} this
26672 * @param {Map event} e
26674 markerRightClick : true,
26676 * @event OverlayViewDraw
26677 * Fires when OverlayView Draw
26678 * @param {Roo.bootstrap.LocationPicker} this
26680 OverlayViewDraw : true,
26682 * @event OverlayViewOnAdd
26683 * Fires when OverlayView Draw
26684 * @param {Roo.bootstrap.LocationPicker} this
26686 OverlayViewOnAdd : true,
26688 * @event OverlayViewOnRemove
26689 * Fires when OverlayView Draw
26690 * @param {Roo.bootstrap.LocationPicker} this
26692 OverlayViewOnRemove : true,
26694 * @event OverlayViewShow
26695 * Fires when OverlayView Draw
26696 * @param {Roo.bootstrap.LocationPicker} this
26697 * @param {Pixel} cpx
26699 OverlayViewShow : true,
26701 * @event OverlayViewHide
26702 * Fires when OverlayView Draw
26703 * @param {Roo.bootstrap.LocationPicker} this
26705 OverlayViewHide : true,
26707 * @event loadexception
26708 * Fires when load google lib failed.
26709 * @param {Roo.bootstrap.LocationPicker} this
26711 loadexception : true
26716 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26718 gMapContext: false,
26724 mapTypeControl: false,
26725 disableDoubleClickZoom: false,
26727 streetViewControl: false,
26731 enableAutocomplete: false,
26732 enableReverseGeocode: true,
26735 getAutoCreate: function()
26740 cls: 'roo-location-picker'
26746 initEvents: function(ct, position)
26748 if(!this.el.getWidth() || this.isApplied()){
26752 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26757 initial: function()
26759 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26760 this.fireEvent('loadexception', this);
26764 if(!this.mapTypeId){
26765 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26768 this.gMapContext = this.GMapContext();
26770 this.initOverlayView();
26772 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26776 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26777 _this.setPosition(_this.gMapContext.marker.position);
26780 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26781 _this.fireEvent('mapClick', this, event);
26785 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26786 _this.fireEvent('mapRightClick', this, event);
26790 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26791 _this.fireEvent('markerClick', this, event);
26795 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26796 _this.fireEvent('markerRightClick', this, event);
26800 this.setPosition(this.gMapContext.location);
26802 this.fireEvent('initial', this, this.gMapContext.location);
26805 initOverlayView: function()
26809 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26813 _this.fireEvent('OverlayViewDraw', _this);
26818 _this.fireEvent('OverlayViewOnAdd', _this);
26821 onRemove: function()
26823 _this.fireEvent('OverlayViewOnRemove', _this);
26826 show: function(cpx)
26828 _this.fireEvent('OverlayViewShow', _this, cpx);
26833 _this.fireEvent('OverlayViewHide', _this);
26839 fromLatLngToContainerPixel: function(event)
26841 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26844 isApplied: function()
26846 return this.getGmapContext() == false ? false : true;
26849 getGmapContext: function()
26851 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26854 GMapContext: function()
26856 var position = new google.maps.LatLng(this.latitude, this.longitude);
26858 var _map = new google.maps.Map(this.el.dom, {
26861 mapTypeId: this.mapTypeId,
26862 mapTypeControl: this.mapTypeControl,
26863 disableDoubleClickZoom: this.disableDoubleClickZoom,
26864 scrollwheel: this.scrollwheel,
26865 streetViewControl: this.streetViewControl,
26866 locationName: this.locationName,
26867 draggable: this.draggable,
26868 enableAutocomplete: this.enableAutocomplete,
26869 enableReverseGeocode: this.enableReverseGeocode
26872 var _marker = new google.maps.Marker({
26873 position: position,
26875 title: this.markerTitle,
26876 draggable: this.draggable
26883 location: position,
26884 radius: this.radius,
26885 locationName: this.locationName,
26886 addressComponents: {
26887 formatted_address: null,
26888 addressLine1: null,
26889 addressLine2: null,
26891 streetNumber: null,
26895 stateOrProvince: null
26898 domContainer: this.el.dom,
26899 geodecoder: new google.maps.Geocoder()
26903 drawCircle: function(center, radius, options)
26905 if (this.gMapContext.circle != null) {
26906 this.gMapContext.circle.setMap(null);
26910 options = Roo.apply({}, options, {
26911 strokeColor: "#0000FF",
26912 strokeOpacity: .35,
26914 fillColor: "#0000FF",
26918 options.map = this.gMapContext.map;
26919 options.radius = radius;
26920 options.center = center;
26921 this.gMapContext.circle = new google.maps.Circle(options);
26922 return this.gMapContext.circle;
26928 setPosition: function(location)
26930 this.gMapContext.location = location;
26931 this.gMapContext.marker.setPosition(location);
26932 this.gMapContext.map.panTo(location);
26933 this.drawCircle(location, this.gMapContext.radius, {});
26937 if (this.gMapContext.settings.enableReverseGeocode) {
26938 this.gMapContext.geodecoder.geocode({
26939 latLng: this.gMapContext.location
26940 }, function(results, status) {
26942 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26943 _this.gMapContext.locationName = results[0].formatted_address;
26944 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26946 _this.fireEvent('positionchanged', this, location);
26953 this.fireEvent('positionchanged', this, location);
26958 google.maps.event.trigger(this.gMapContext.map, "resize");
26960 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26962 this.fireEvent('resize', this);
26965 setPositionByLatLng: function(latitude, longitude)
26967 this.setPosition(new google.maps.LatLng(latitude, longitude));
26970 getCurrentPosition: function()
26973 latitude: this.gMapContext.location.lat(),
26974 longitude: this.gMapContext.location.lng()
26978 getAddressName: function()
26980 return this.gMapContext.locationName;
26983 getAddressComponents: function()
26985 return this.gMapContext.addressComponents;
26988 address_component_from_google_geocode: function(address_components)
26992 for (var i = 0; i < address_components.length; i++) {
26993 var component = address_components[i];
26994 if (component.types.indexOf("postal_code") >= 0) {
26995 result.postalCode = component.short_name;
26996 } else if (component.types.indexOf("street_number") >= 0) {
26997 result.streetNumber = component.short_name;
26998 } else if (component.types.indexOf("route") >= 0) {
26999 result.streetName = component.short_name;
27000 } else if (component.types.indexOf("neighborhood") >= 0) {
27001 result.city = component.short_name;
27002 } else if (component.types.indexOf("locality") >= 0) {
27003 result.city = component.short_name;
27004 } else if (component.types.indexOf("sublocality") >= 0) {
27005 result.district = component.short_name;
27006 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27007 result.stateOrProvince = component.short_name;
27008 } else if (component.types.indexOf("country") >= 0) {
27009 result.country = component.short_name;
27013 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27014 result.addressLine2 = "";
27018 setZoomLevel: function(zoom)
27020 this.gMapContext.map.setZoom(zoom);
27033 this.fireEvent('show', this);
27044 this.fireEvent('hide', this);
27049 Roo.apply(Roo.bootstrap.LocationPicker, {
27051 OverlayView : function(map, options)
27053 options = options || {};
27067 * @class Roo.bootstrap.Alert
27068 * @extends Roo.bootstrap.Component
27069 * Bootstrap Alert class
27070 * @cfg {String} title The title of alert
27071 * @cfg {String} html The content of alert
27072 * @cfg {String} weight ( success | info | warning | danger )
27073 * @cfg {String} faicon font-awesomeicon
27076 * Create a new alert
27077 * @param {Object} config The config object
27081 Roo.bootstrap.Alert = function(config){
27082 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27086 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27093 getAutoCreate : function()
27102 cls : 'roo-alert-icon'
27107 cls : 'roo-alert-title',
27112 cls : 'roo-alert-text',
27119 cfg.cn[0].cls += ' fa ' + this.faicon;
27123 cfg.cls += ' alert-' + this.weight;
27129 initEvents: function()
27131 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27134 setTitle : function(str)
27136 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27139 setText : function(str)
27141 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27144 setWeight : function(weight)
27147 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27150 this.weight = weight;
27152 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27155 setIcon : function(icon)
27158 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27161 this.faicon = icon;
27163 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27184 * @class Roo.bootstrap.UploadCropbox
27185 * @extends Roo.bootstrap.Component
27186 * Bootstrap UploadCropbox class
27187 * @cfg {String} emptyText show when image has been loaded
27188 * @cfg {String} rotateNotify show when image too small to rotate
27189 * @cfg {Number} errorTimeout default 3000
27190 * @cfg {Number} minWidth default 300
27191 * @cfg {Number} minHeight default 300
27192 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27193 * @cfg {Boolean} isDocument (true|false) default false
27194 * @cfg {String} url action url
27195 * @cfg {String} paramName default 'imageUpload'
27196 * @cfg {String} method default POST
27197 * @cfg {Boolean} loadMask (true|false) default true
27198 * @cfg {Boolean} loadingText default 'Loading...'
27201 * Create a new UploadCropbox
27202 * @param {Object} config The config object
27205 Roo.bootstrap.UploadCropbox = function(config){
27206 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27210 * @event beforeselectfile
27211 * Fire before select file
27212 * @param {Roo.bootstrap.UploadCropbox} this
27214 "beforeselectfile" : true,
27217 * Fire after initEvent
27218 * @param {Roo.bootstrap.UploadCropbox} this
27223 * Fire after initEvent
27224 * @param {Roo.bootstrap.UploadCropbox} this
27225 * @param {String} data
27230 * Fire when preparing the file data
27231 * @param {Roo.bootstrap.UploadCropbox} this
27232 * @param {Object} file
27237 * Fire when get exception
27238 * @param {Roo.bootstrap.UploadCropbox} this
27239 * @param {XMLHttpRequest} xhr
27241 "exception" : true,
27243 * @event beforeloadcanvas
27244 * Fire before load the canvas
27245 * @param {Roo.bootstrap.UploadCropbox} this
27246 * @param {String} src
27248 "beforeloadcanvas" : true,
27251 * Fire when trash image
27252 * @param {Roo.bootstrap.UploadCropbox} this
27257 * Fire when download the image
27258 * @param {Roo.bootstrap.UploadCropbox} this
27262 * @event footerbuttonclick
27263 * Fire when footerbuttonclick
27264 * @param {Roo.bootstrap.UploadCropbox} this
27265 * @param {String} type
27267 "footerbuttonclick" : true,
27271 * @param {Roo.bootstrap.UploadCropbox} this
27276 * Fire when rotate the image
27277 * @param {Roo.bootstrap.UploadCropbox} this
27278 * @param {String} pos
27283 * Fire when inspect the file
27284 * @param {Roo.bootstrap.UploadCropbox} this
27285 * @param {Object} file
27290 * Fire when xhr upload the file
27291 * @param {Roo.bootstrap.UploadCropbox} this
27292 * @param {Object} data
27297 * Fire when arrange the file data
27298 * @param {Roo.bootstrap.UploadCropbox} this
27299 * @param {Object} formData
27304 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27307 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27309 emptyText : 'Click to upload image',
27310 rotateNotify : 'Image is too small to rotate',
27311 errorTimeout : 3000,
27325 cropType : 'image/jpeg',
27327 canvasLoaded : false,
27328 isDocument : false,
27330 paramName : 'imageUpload',
27332 loadingText : 'Loading...',
27335 getAutoCreate : function()
27339 cls : 'roo-upload-cropbox',
27343 cls : 'roo-upload-cropbox-selector',
27348 cls : 'roo-upload-cropbox-body',
27349 style : 'cursor:pointer',
27353 cls : 'roo-upload-cropbox-preview'
27357 cls : 'roo-upload-cropbox-thumb'
27361 cls : 'roo-upload-cropbox-empty-notify',
27362 html : this.emptyText
27366 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27367 html : this.rotateNotify
27373 cls : 'roo-upload-cropbox-footer',
27376 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27386 onRender : function(ct, position)
27388 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27390 if (this.buttons.length) {
27392 Roo.each(this.buttons, function(bb) {
27394 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27396 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27402 this.maskEl = this.el;
27406 initEvents : function()
27408 this.urlAPI = (window.createObjectURL && window) ||
27409 (window.URL && URL.revokeObjectURL && URL) ||
27410 (window.webkitURL && webkitURL);
27412 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27413 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27415 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27416 this.selectorEl.hide();
27418 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27419 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27421 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27422 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27423 this.thumbEl.hide();
27425 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27426 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27428 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27429 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27430 this.errorEl.hide();
27432 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27433 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27434 this.footerEl.hide();
27436 this.setThumbBoxSize();
27442 this.fireEvent('initial', this);
27449 window.addEventListener("resize", function() { _this.resize(); } );
27451 this.bodyEl.on('click', this.beforeSelectFile, this);
27454 this.bodyEl.on('touchstart', this.onTouchStart, this);
27455 this.bodyEl.on('touchmove', this.onTouchMove, this);
27456 this.bodyEl.on('touchend', this.onTouchEnd, this);
27460 this.bodyEl.on('mousedown', this.onMouseDown, this);
27461 this.bodyEl.on('mousemove', this.onMouseMove, this);
27462 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27463 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27464 Roo.get(document).on('mouseup', this.onMouseUp, this);
27467 this.selectorEl.on('change', this.onFileSelected, this);
27473 this.baseScale = 1;
27475 this.baseRotate = 1;
27476 this.dragable = false;
27477 this.pinching = false;
27480 this.cropData = false;
27481 this.notifyEl.dom.innerHTML = this.emptyText;
27483 this.selectorEl.dom.value = '';
27487 resize : function()
27489 if(this.fireEvent('resize', this) != false){
27490 this.setThumbBoxPosition();
27491 this.setCanvasPosition();
27495 onFooterButtonClick : function(e, el, o, type)
27498 case 'rotate-left' :
27499 this.onRotateLeft(e);
27501 case 'rotate-right' :
27502 this.onRotateRight(e);
27505 this.beforeSelectFile(e);
27520 this.fireEvent('footerbuttonclick', this, type);
27523 beforeSelectFile : function(e)
27525 e.preventDefault();
27527 if(this.fireEvent('beforeselectfile', this) != false){
27528 this.selectorEl.dom.click();
27532 onFileSelected : function(e)
27534 e.preventDefault();
27536 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27540 var file = this.selectorEl.dom.files[0];
27542 if(this.fireEvent('inspect', this, file) != false){
27543 this.prepare(file);
27548 trash : function(e)
27550 this.fireEvent('trash', this);
27553 download : function(e)
27555 this.fireEvent('download', this);
27558 loadCanvas : function(src)
27560 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27564 this.imageEl = document.createElement('img');
27568 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27570 this.imageEl.src = src;
27574 onLoadCanvas : function()
27576 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27577 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27579 this.bodyEl.un('click', this.beforeSelectFile, this);
27581 this.notifyEl.hide();
27582 this.thumbEl.show();
27583 this.footerEl.show();
27585 this.baseRotateLevel();
27587 if(this.isDocument){
27588 this.setThumbBoxSize();
27591 this.setThumbBoxPosition();
27593 this.baseScaleLevel();
27599 this.canvasLoaded = true;
27602 this.maskEl.unmask();
27607 setCanvasPosition : function()
27609 if(!this.canvasEl){
27613 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27614 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27616 this.previewEl.setLeft(pw);
27617 this.previewEl.setTop(ph);
27621 onMouseDown : function(e)
27625 this.dragable = true;
27626 this.pinching = false;
27628 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27629 this.dragable = false;
27633 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27634 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27638 onMouseMove : function(e)
27642 if(!this.canvasLoaded){
27646 if (!this.dragable){
27650 var minX = Math.ceil(this.thumbEl.getLeft(true));
27651 var minY = Math.ceil(this.thumbEl.getTop(true));
27653 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27654 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27656 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27657 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27659 x = x - this.mouseX;
27660 y = y - this.mouseY;
27662 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27663 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27665 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27666 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27668 this.previewEl.setLeft(bgX);
27669 this.previewEl.setTop(bgY);
27671 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27672 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27675 onMouseUp : function(e)
27679 this.dragable = false;
27682 onMouseWheel : function(e)
27686 this.startScale = this.scale;
27688 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27690 if(!this.zoomable()){
27691 this.scale = this.startScale;
27700 zoomable : function()
27702 var minScale = this.thumbEl.getWidth() / this.minWidth;
27704 if(this.minWidth < this.minHeight){
27705 minScale = this.thumbEl.getHeight() / this.minHeight;
27708 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27709 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27713 (this.rotate == 0 || this.rotate == 180) &&
27715 width > this.imageEl.OriginWidth ||
27716 height > this.imageEl.OriginHeight ||
27717 (width < this.minWidth && height < this.minHeight)
27725 (this.rotate == 90 || this.rotate == 270) &&
27727 width > this.imageEl.OriginWidth ||
27728 height > this.imageEl.OriginHeight ||
27729 (width < this.minHeight && height < this.minWidth)
27736 !this.isDocument &&
27737 (this.rotate == 0 || this.rotate == 180) &&
27739 width < this.minWidth ||
27740 width > this.imageEl.OriginWidth ||
27741 height < this.minHeight ||
27742 height > this.imageEl.OriginHeight
27749 !this.isDocument &&
27750 (this.rotate == 90 || this.rotate == 270) &&
27752 width < this.minHeight ||
27753 width > this.imageEl.OriginWidth ||
27754 height < this.minWidth ||
27755 height > this.imageEl.OriginHeight
27765 onRotateLeft : function(e)
27767 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27769 var minScale = this.thumbEl.getWidth() / this.minWidth;
27771 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27772 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27774 this.startScale = this.scale;
27776 while (this.getScaleLevel() < minScale){
27778 this.scale = this.scale + 1;
27780 if(!this.zoomable()){
27785 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27786 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27791 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27798 this.scale = this.startScale;
27800 this.onRotateFail();
27805 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27807 if(this.isDocument){
27808 this.setThumbBoxSize();
27809 this.setThumbBoxPosition();
27810 this.setCanvasPosition();
27815 this.fireEvent('rotate', this, 'left');
27819 onRotateRight : function(e)
27821 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27823 var minScale = this.thumbEl.getWidth() / this.minWidth;
27825 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27826 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27828 this.startScale = this.scale;
27830 while (this.getScaleLevel() < minScale){
27832 this.scale = this.scale + 1;
27834 if(!this.zoomable()){
27839 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27840 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27845 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27852 this.scale = this.startScale;
27854 this.onRotateFail();
27859 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27861 if(this.isDocument){
27862 this.setThumbBoxSize();
27863 this.setThumbBoxPosition();
27864 this.setCanvasPosition();
27869 this.fireEvent('rotate', this, 'right');
27872 onRotateFail : function()
27874 this.errorEl.show(true);
27878 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27883 this.previewEl.dom.innerHTML = '';
27885 var canvasEl = document.createElement("canvas");
27887 var contextEl = canvasEl.getContext("2d");
27889 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27890 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27891 var center = this.imageEl.OriginWidth / 2;
27893 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27894 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27895 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27896 center = this.imageEl.OriginHeight / 2;
27899 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27901 contextEl.translate(center, center);
27902 contextEl.rotate(this.rotate * Math.PI / 180);
27904 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27906 this.canvasEl = document.createElement("canvas");
27908 this.contextEl = this.canvasEl.getContext("2d");
27910 switch (this.rotate) {
27913 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27914 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27916 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27921 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27922 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27924 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27925 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);
27929 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27934 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27935 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27937 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27938 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);
27942 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);
27947 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27948 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27950 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27951 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27955 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);
27962 this.previewEl.appendChild(this.canvasEl);
27964 this.setCanvasPosition();
27969 if(!this.canvasLoaded){
27973 var imageCanvas = document.createElement("canvas");
27975 var imageContext = imageCanvas.getContext("2d");
27977 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27978 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27980 var center = imageCanvas.width / 2;
27982 imageContext.translate(center, center);
27984 imageContext.rotate(this.rotate * Math.PI / 180);
27986 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27988 var canvas = document.createElement("canvas");
27990 var context = canvas.getContext("2d");
27992 canvas.width = this.minWidth;
27993 canvas.height = this.minHeight;
27995 switch (this.rotate) {
27998 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27999 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28001 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28002 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28004 var targetWidth = this.minWidth - 2 * x;
28005 var targetHeight = this.minHeight - 2 * y;
28009 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28010 scale = targetWidth / width;
28013 if(x > 0 && y == 0){
28014 scale = targetHeight / height;
28017 if(x > 0 && y > 0){
28018 scale = targetWidth / width;
28020 if(width < height){
28021 scale = targetHeight / height;
28025 context.scale(scale, scale);
28027 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28028 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28030 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28031 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28033 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28038 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28039 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28041 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28042 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28044 var targetWidth = this.minWidth - 2 * x;
28045 var targetHeight = this.minHeight - 2 * y;
28049 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28050 scale = targetWidth / width;
28053 if(x > 0 && y == 0){
28054 scale = targetHeight / height;
28057 if(x > 0 && y > 0){
28058 scale = targetWidth / width;
28060 if(width < height){
28061 scale = targetHeight / height;
28065 context.scale(scale, scale);
28067 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28068 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28070 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28071 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28073 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28075 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28080 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28081 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28083 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28084 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28086 var targetWidth = this.minWidth - 2 * x;
28087 var targetHeight = this.minHeight - 2 * y;
28091 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28092 scale = targetWidth / width;
28095 if(x > 0 && y == 0){
28096 scale = targetHeight / height;
28099 if(x > 0 && y > 0){
28100 scale = targetWidth / width;
28102 if(width < height){
28103 scale = targetHeight / height;
28107 context.scale(scale, scale);
28109 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28110 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28112 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28113 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28115 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28116 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28118 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28123 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28124 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28126 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28127 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28129 var targetWidth = this.minWidth - 2 * x;
28130 var targetHeight = this.minHeight - 2 * y;
28134 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28135 scale = targetWidth / width;
28138 if(x > 0 && y == 0){
28139 scale = targetHeight / height;
28142 if(x > 0 && y > 0){
28143 scale = targetWidth / width;
28145 if(width < height){
28146 scale = targetHeight / height;
28150 context.scale(scale, scale);
28152 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28153 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28155 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28156 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28158 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28160 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28167 this.cropData = canvas.toDataURL(this.cropType);
28169 if(this.fireEvent('crop', this, this.cropData) !== false){
28170 this.process(this.file, this.cropData);
28177 setThumbBoxSize : function()
28181 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28182 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28183 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28185 this.minWidth = width;
28186 this.minHeight = height;
28188 if(this.rotate == 90 || this.rotate == 270){
28189 this.minWidth = height;
28190 this.minHeight = width;
28195 width = Math.ceil(this.minWidth * height / this.minHeight);
28197 if(this.minWidth > this.minHeight){
28199 height = Math.ceil(this.minHeight * width / this.minWidth);
28202 this.thumbEl.setStyle({
28203 width : width + 'px',
28204 height : height + 'px'
28211 setThumbBoxPosition : function()
28213 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28214 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28216 this.thumbEl.setLeft(x);
28217 this.thumbEl.setTop(y);
28221 baseRotateLevel : function()
28223 this.baseRotate = 1;
28226 typeof(this.exif) != 'undefined' &&
28227 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28228 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28230 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28233 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28237 baseScaleLevel : function()
28241 if(this.isDocument){
28243 if(this.baseRotate == 6 || this.baseRotate == 8){
28245 height = this.thumbEl.getHeight();
28246 this.baseScale = height / this.imageEl.OriginWidth;
28248 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28249 width = this.thumbEl.getWidth();
28250 this.baseScale = width / this.imageEl.OriginHeight;
28256 height = this.thumbEl.getHeight();
28257 this.baseScale = height / this.imageEl.OriginHeight;
28259 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28260 width = this.thumbEl.getWidth();
28261 this.baseScale = width / this.imageEl.OriginWidth;
28267 if(this.baseRotate == 6 || this.baseRotate == 8){
28269 width = this.thumbEl.getHeight();
28270 this.baseScale = width / this.imageEl.OriginHeight;
28272 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28273 height = this.thumbEl.getWidth();
28274 this.baseScale = height / this.imageEl.OriginHeight;
28277 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28278 height = this.thumbEl.getWidth();
28279 this.baseScale = height / this.imageEl.OriginHeight;
28281 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28282 width = this.thumbEl.getHeight();
28283 this.baseScale = width / this.imageEl.OriginWidth;
28290 width = this.thumbEl.getWidth();
28291 this.baseScale = width / this.imageEl.OriginWidth;
28293 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28294 height = this.thumbEl.getHeight();
28295 this.baseScale = height / this.imageEl.OriginHeight;
28298 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28300 height = this.thumbEl.getHeight();
28301 this.baseScale = height / this.imageEl.OriginHeight;
28303 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28304 width = this.thumbEl.getWidth();
28305 this.baseScale = width / this.imageEl.OriginWidth;
28313 getScaleLevel : function()
28315 return this.baseScale * Math.pow(1.1, this.scale);
28318 onTouchStart : function(e)
28320 if(!this.canvasLoaded){
28321 this.beforeSelectFile(e);
28325 var touches = e.browserEvent.touches;
28331 if(touches.length == 1){
28332 this.onMouseDown(e);
28336 if(touches.length != 2){
28342 for(var i = 0, finger; finger = touches[i]; i++){
28343 coords.push(finger.pageX, finger.pageY);
28346 var x = Math.pow(coords[0] - coords[2], 2);
28347 var y = Math.pow(coords[1] - coords[3], 2);
28349 this.startDistance = Math.sqrt(x + y);
28351 this.startScale = this.scale;
28353 this.pinching = true;
28354 this.dragable = false;
28358 onTouchMove : function(e)
28360 if(!this.pinching && !this.dragable){
28364 var touches = e.browserEvent.touches;
28371 this.onMouseMove(e);
28377 for(var i = 0, finger; finger = touches[i]; i++){
28378 coords.push(finger.pageX, finger.pageY);
28381 var x = Math.pow(coords[0] - coords[2], 2);
28382 var y = Math.pow(coords[1] - coords[3], 2);
28384 this.endDistance = Math.sqrt(x + y);
28386 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28388 if(!this.zoomable()){
28389 this.scale = this.startScale;
28397 onTouchEnd : function(e)
28399 this.pinching = false;
28400 this.dragable = false;
28404 process : function(file, crop)
28407 this.maskEl.mask(this.loadingText);
28410 this.xhr = new XMLHttpRequest();
28412 file.xhr = this.xhr;
28414 this.xhr.open(this.method, this.url, true);
28417 "Accept": "application/json",
28418 "Cache-Control": "no-cache",
28419 "X-Requested-With": "XMLHttpRequest"
28422 for (var headerName in headers) {
28423 var headerValue = headers[headerName];
28425 this.xhr.setRequestHeader(headerName, headerValue);
28431 this.xhr.onload = function()
28433 _this.xhrOnLoad(_this.xhr);
28436 this.xhr.onerror = function()
28438 _this.xhrOnError(_this.xhr);
28441 var formData = new FormData();
28443 formData.append('returnHTML', 'NO');
28446 formData.append('crop', crop);
28449 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28450 formData.append(this.paramName, file, file.name);
28453 if(typeof(file.filename) != 'undefined'){
28454 formData.append('filename', file.filename);
28457 if(typeof(file.mimetype) != 'undefined'){
28458 formData.append('mimetype', file.mimetype);
28461 if(this.fireEvent('arrange', this, formData) != false){
28462 this.xhr.send(formData);
28466 xhrOnLoad : function(xhr)
28469 this.maskEl.unmask();
28472 if (xhr.readyState !== 4) {
28473 this.fireEvent('exception', this, xhr);
28477 var response = Roo.decode(xhr.responseText);
28479 if(!response.success){
28480 this.fireEvent('exception', this, xhr);
28484 var response = Roo.decode(xhr.responseText);
28486 this.fireEvent('upload', this, response);
28490 xhrOnError : function()
28493 this.maskEl.unmask();
28496 Roo.log('xhr on error');
28498 var response = Roo.decode(xhr.responseText);
28504 prepare : function(file)
28507 this.maskEl.mask(this.loadingText);
28513 if(typeof(file) === 'string'){
28514 this.loadCanvas(file);
28518 if(!file || !this.urlAPI){
28523 this.cropType = file.type;
28527 if(this.fireEvent('prepare', this, this.file) != false){
28529 var reader = new FileReader();
28531 reader.onload = function (e) {
28532 if (e.target.error) {
28533 Roo.log(e.target.error);
28537 var buffer = e.target.result,
28538 dataView = new DataView(buffer),
28540 maxOffset = dataView.byteLength - 4,
28544 if (dataView.getUint16(0) === 0xffd8) {
28545 while (offset < maxOffset) {
28546 markerBytes = dataView.getUint16(offset);
28548 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28549 markerLength = dataView.getUint16(offset + 2) + 2;
28550 if (offset + markerLength > dataView.byteLength) {
28551 Roo.log('Invalid meta data: Invalid segment size.');
28555 if(markerBytes == 0xffe1){
28556 _this.parseExifData(
28563 offset += markerLength;
28573 var url = _this.urlAPI.createObjectURL(_this.file);
28575 _this.loadCanvas(url);
28580 reader.readAsArrayBuffer(this.file);
28586 parseExifData : function(dataView, offset, length)
28588 var tiffOffset = offset + 10,
28592 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28593 // No Exif data, might be XMP data instead
28597 // Check for the ASCII code for "Exif" (0x45786966):
28598 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28599 // No Exif data, might be XMP data instead
28602 if (tiffOffset + 8 > dataView.byteLength) {
28603 Roo.log('Invalid Exif data: Invalid segment size.');
28606 // Check for the two null bytes:
28607 if (dataView.getUint16(offset + 8) !== 0x0000) {
28608 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28611 // Check the byte alignment:
28612 switch (dataView.getUint16(tiffOffset)) {
28614 littleEndian = true;
28617 littleEndian = false;
28620 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28623 // Check for the TIFF tag marker (0x002A):
28624 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28625 Roo.log('Invalid Exif data: Missing TIFF marker.');
28628 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28629 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28631 this.parseExifTags(
28634 tiffOffset + dirOffset,
28639 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28644 if (dirOffset + 6 > dataView.byteLength) {
28645 Roo.log('Invalid Exif data: Invalid directory offset.');
28648 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28649 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28650 if (dirEndOffset + 4 > dataView.byteLength) {
28651 Roo.log('Invalid Exif data: Invalid directory size.');
28654 for (i = 0; i < tagsNumber; i += 1) {
28658 dirOffset + 2 + 12 * i, // tag offset
28662 // Return the offset to the next directory:
28663 return dataView.getUint32(dirEndOffset, littleEndian);
28666 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28668 var tag = dataView.getUint16(offset, littleEndian);
28670 this.exif[tag] = this.getExifValue(
28674 dataView.getUint16(offset + 2, littleEndian), // tag type
28675 dataView.getUint32(offset + 4, littleEndian), // tag length
28680 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28682 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28691 Roo.log('Invalid Exif data: Invalid tag type.');
28695 tagSize = tagType.size * length;
28696 // Determine if the value is contained in the dataOffset bytes,
28697 // or if the value at the dataOffset is a pointer to the actual data:
28698 dataOffset = tagSize > 4 ?
28699 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28700 if (dataOffset + tagSize > dataView.byteLength) {
28701 Roo.log('Invalid Exif data: Invalid data offset.');
28704 if (length === 1) {
28705 return tagType.getValue(dataView, dataOffset, littleEndian);
28708 for (i = 0; i < length; i += 1) {
28709 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28712 if (tagType.ascii) {
28714 // Concatenate the chars:
28715 for (i = 0; i < values.length; i += 1) {
28717 // Ignore the terminating NULL byte(s):
28718 if (c === '\u0000') {
28730 Roo.apply(Roo.bootstrap.UploadCropbox, {
28732 'Orientation': 0x0112
28736 1: 0, //'top-left',
28738 3: 180, //'bottom-right',
28739 // 4: 'bottom-left',
28741 6: 90, //'right-top',
28742 // 7: 'right-bottom',
28743 8: 270 //'left-bottom'
28747 // byte, 8-bit unsigned int:
28749 getValue: function (dataView, dataOffset) {
28750 return dataView.getUint8(dataOffset);
28754 // ascii, 8-bit byte:
28756 getValue: function (dataView, dataOffset) {
28757 return String.fromCharCode(dataView.getUint8(dataOffset));
28762 // short, 16 bit int:
28764 getValue: function (dataView, dataOffset, littleEndian) {
28765 return dataView.getUint16(dataOffset, littleEndian);
28769 // long, 32 bit int:
28771 getValue: function (dataView, dataOffset, littleEndian) {
28772 return dataView.getUint32(dataOffset, littleEndian);
28776 // rational = two long values, first is numerator, second is denominator:
28778 getValue: function (dataView, dataOffset, littleEndian) {
28779 return dataView.getUint32(dataOffset, littleEndian) /
28780 dataView.getUint32(dataOffset + 4, littleEndian);
28784 // slong, 32 bit signed int:
28786 getValue: function (dataView, dataOffset, littleEndian) {
28787 return dataView.getInt32(dataOffset, littleEndian);
28791 // srational, two slongs, first is numerator, second is denominator:
28793 getValue: function (dataView, dataOffset, littleEndian) {
28794 return dataView.getInt32(dataOffset, littleEndian) /
28795 dataView.getInt32(dataOffset + 4, littleEndian);
28805 cls : 'btn-group roo-upload-cropbox-rotate-left',
28806 action : 'rotate-left',
28810 cls : 'btn btn-default',
28811 html : '<i class="fa fa-undo"></i>'
28817 cls : 'btn-group roo-upload-cropbox-picture',
28818 action : 'picture',
28822 cls : 'btn btn-default',
28823 html : '<i class="fa fa-picture-o"></i>'
28829 cls : 'btn-group roo-upload-cropbox-rotate-right',
28830 action : 'rotate-right',
28834 cls : 'btn btn-default',
28835 html : '<i class="fa fa-repeat"></i>'
28843 cls : 'btn-group roo-upload-cropbox-rotate-left',
28844 action : 'rotate-left',
28848 cls : 'btn btn-default',
28849 html : '<i class="fa fa-undo"></i>'
28855 cls : 'btn-group roo-upload-cropbox-download',
28856 action : 'download',
28860 cls : 'btn btn-default',
28861 html : '<i class="fa fa-download"></i>'
28867 cls : 'btn-group roo-upload-cropbox-crop',
28872 cls : 'btn btn-default',
28873 html : '<i class="fa fa-crop"></i>'
28879 cls : 'btn-group roo-upload-cropbox-trash',
28884 cls : 'btn btn-default',
28885 html : '<i class="fa fa-trash"></i>'
28891 cls : 'btn-group roo-upload-cropbox-rotate-right',
28892 action : 'rotate-right',
28896 cls : 'btn btn-default',
28897 html : '<i class="fa fa-repeat"></i>'
28905 cls : 'btn-group roo-upload-cropbox-rotate-left',
28906 action : 'rotate-left',
28910 cls : 'btn btn-default',
28911 html : '<i class="fa fa-undo"></i>'
28917 cls : 'btn-group roo-upload-cropbox-rotate-right',
28918 action : 'rotate-right',
28922 cls : 'btn btn-default',
28923 html : '<i class="fa fa-repeat"></i>'
28936 * @class Roo.bootstrap.DocumentManager
28937 * @extends Roo.bootstrap.Component
28938 * Bootstrap DocumentManager class
28939 * @cfg {String} paramName default 'imageUpload'
28940 * @cfg {String} toolTipName default 'filename'
28941 * @cfg {String} method default POST
28942 * @cfg {String} url action url
28943 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28944 * @cfg {Boolean} multiple multiple upload default true
28945 * @cfg {Number} thumbSize default 300
28946 * @cfg {String} fieldLabel
28947 * @cfg {Number} labelWidth default 4
28948 * @cfg {String} labelAlign (left|top) default left
28949 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28950 * @cfg {Number} labellg set the width of label (1-12)
28951 * @cfg {Number} labelmd set the width of label (1-12)
28952 * @cfg {Number} labelsm set the width of label (1-12)
28953 * @cfg {Number} labelxs set the width of label (1-12)
28956 * Create a new DocumentManager
28957 * @param {Object} config The config object
28960 Roo.bootstrap.DocumentManager = function(config){
28961 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28964 this.delegates = [];
28969 * Fire when initial the DocumentManager
28970 * @param {Roo.bootstrap.DocumentManager} this
28975 * inspect selected file
28976 * @param {Roo.bootstrap.DocumentManager} this
28977 * @param {File} file
28982 * Fire when xhr load exception
28983 * @param {Roo.bootstrap.DocumentManager} this
28984 * @param {XMLHttpRequest} xhr
28986 "exception" : true,
28988 * @event afterupload
28989 * Fire when xhr load exception
28990 * @param {Roo.bootstrap.DocumentManager} this
28991 * @param {XMLHttpRequest} xhr
28993 "afterupload" : true,
28996 * prepare the form data
28997 * @param {Roo.bootstrap.DocumentManager} this
28998 * @param {Object} formData
29003 * Fire when remove the file
29004 * @param {Roo.bootstrap.DocumentManager} this
29005 * @param {Object} file
29010 * Fire after refresh the file
29011 * @param {Roo.bootstrap.DocumentManager} this
29016 * Fire after click the image
29017 * @param {Roo.bootstrap.DocumentManager} this
29018 * @param {Object} file
29023 * Fire when upload a image and editable set to true
29024 * @param {Roo.bootstrap.DocumentManager} this
29025 * @param {Object} file
29029 * @event beforeselectfile
29030 * Fire before select file
29031 * @param {Roo.bootstrap.DocumentManager} this
29033 "beforeselectfile" : true,
29036 * Fire before process file
29037 * @param {Roo.bootstrap.DocumentManager} this
29038 * @param {Object} file
29042 * @event previewrendered
29043 * Fire when preview rendered
29044 * @param {Roo.bootstrap.DocumentManager} this
29045 * @param {Object} file
29047 "previewrendered" : true,
29050 "previewResize" : true
29055 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29064 paramName : 'imageUpload',
29065 toolTipName : 'filename',
29068 labelAlign : 'left',
29078 getAutoCreate : function()
29080 var managerWidget = {
29082 cls : 'roo-document-manager',
29086 cls : 'roo-document-manager-selector',
29091 cls : 'roo-document-manager-uploader',
29095 cls : 'roo-document-manager-upload-btn',
29096 html : '<i class="fa fa-plus"></i>'
29107 cls : 'column col-md-12',
29112 if(this.fieldLabel.length){
29117 cls : 'column col-md-12',
29118 html : this.fieldLabel
29122 cls : 'column col-md-12',
29127 if(this.labelAlign == 'left'){
29132 html : this.fieldLabel
29141 if(this.labelWidth > 12){
29142 content[0].style = "width: " + this.labelWidth + 'px';
29145 if(this.labelWidth < 13 && this.labelmd == 0){
29146 this.labelmd = this.labelWidth;
29149 if(this.labellg > 0){
29150 content[0].cls += ' col-lg-' + this.labellg;
29151 content[1].cls += ' col-lg-' + (12 - this.labellg);
29154 if(this.labelmd > 0){
29155 content[0].cls += ' col-md-' + this.labelmd;
29156 content[1].cls += ' col-md-' + (12 - this.labelmd);
29159 if(this.labelsm > 0){
29160 content[0].cls += ' col-sm-' + this.labelsm;
29161 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29164 if(this.labelxs > 0){
29165 content[0].cls += ' col-xs-' + this.labelxs;
29166 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29174 cls : 'row clearfix',
29182 initEvents : function()
29184 this.managerEl = this.el.select('.roo-document-manager', true).first();
29185 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29187 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29188 this.selectorEl.hide();
29191 this.selectorEl.attr('multiple', 'multiple');
29194 this.selectorEl.on('change', this.onFileSelected, this);
29196 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29197 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29199 this.uploader.on('click', this.onUploaderClick, this);
29201 this.renderProgressDialog();
29205 window.addEventListener("resize", function() { _this.refresh(); } );
29207 this.fireEvent('initial', this);
29210 renderProgressDialog : function()
29214 this.progressDialog = new Roo.bootstrap.Modal({
29215 cls : 'roo-document-manager-progress-dialog',
29216 allow_close : false,
29227 btnclick : function() {
29228 _this.uploadCancel();
29234 this.progressDialog.render(Roo.get(document.body));
29236 this.progress = new Roo.bootstrap.Progress({
29237 cls : 'roo-document-manager-progress',
29242 this.progress.render(this.progressDialog.getChildContainer());
29244 this.progressBar = new Roo.bootstrap.ProgressBar({
29245 cls : 'roo-document-manager-progress-bar',
29248 aria_valuemax : 12,
29252 this.progressBar.render(this.progress.getChildContainer());
29255 onUploaderClick : function(e)
29257 e.preventDefault();
29259 if(this.fireEvent('beforeselectfile', this) != false){
29260 this.selectorEl.dom.click();
29265 onFileSelected : function(e)
29267 e.preventDefault();
29269 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29273 Roo.each(this.selectorEl.dom.files, function(file){
29274 if(this.fireEvent('inspect', this, file) != false){
29275 this.files.push(file);
29285 this.selectorEl.dom.value = '';
29287 if(!this.files || !this.files.length){
29291 if(this.boxes > 0 && this.files.length > this.boxes){
29292 this.files = this.files.slice(0, this.boxes);
29295 this.uploader.show();
29297 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29298 this.uploader.hide();
29307 Roo.each(this.files, function(file){
29309 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29310 var f = this.renderPreview(file);
29315 if(file.type.indexOf('image') != -1){
29316 this.delegates.push(
29318 _this.process(file);
29319 }).createDelegate(this)
29327 _this.process(file);
29328 }).createDelegate(this)
29333 this.files = files;
29335 this.delegates = this.delegates.concat(docs);
29337 if(!this.delegates.length){
29342 this.progressBar.aria_valuemax = this.delegates.length;
29349 arrange : function()
29351 if(!this.delegates.length){
29352 this.progressDialog.hide();
29357 var delegate = this.delegates.shift();
29359 this.progressDialog.show();
29361 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29363 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29368 refresh : function()
29370 this.uploader.show();
29372 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29373 this.uploader.hide();
29376 Roo.isTouch ? this.closable(false) : this.closable(true);
29378 this.fireEvent('refresh', this);
29381 onRemove : function(e, el, o)
29383 e.preventDefault();
29385 this.fireEvent('remove', this, o);
29389 remove : function(o)
29393 Roo.each(this.files, function(file){
29394 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29403 this.files = files;
29410 Roo.each(this.files, function(file){
29415 file.target.remove();
29424 onClick : function(e, el, o)
29426 e.preventDefault();
29428 this.fireEvent('click', this, o);
29432 closable : function(closable)
29434 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29436 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29448 xhrOnLoad : function(xhr)
29450 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29454 if (xhr.readyState !== 4) {
29456 this.fireEvent('exception', this, xhr);
29460 var response = Roo.decode(xhr.responseText);
29462 if(!response.success){
29464 this.fireEvent('exception', this, xhr);
29468 var file = this.renderPreview(response.data);
29470 this.files.push(file);
29474 this.fireEvent('afterupload', this, xhr);
29478 xhrOnError : function(xhr)
29480 Roo.log('xhr on error');
29482 var response = Roo.decode(xhr.responseText);
29489 process : function(file)
29491 if(this.fireEvent('process', this, file) !== false){
29492 if(this.editable && file.type.indexOf('image') != -1){
29493 this.fireEvent('edit', this, file);
29497 this.uploadStart(file, false);
29504 uploadStart : function(file, crop)
29506 this.xhr = new XMLHttpRequest();
29508 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29513 file.xhr = this.xhr;
29515 this.managerEl.createChild({
29517 cls : 'roo-document-manager-loading',
29521 tooltip : file.name,
29522 cls : 'roo-document-manager-thumb',
29523 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29529 this.xhr.open(this.method, this.url, true);
29532 "Accept": "application/json",
29533 "Cache-Control": "no-cache",
29534 "X-Requested-With": "XMLHttpRequest"
29537 for (var headerName in headers) {
29538 var headerValue = headers[headerName];
29540 this.xhr.setRequestHeader(headerName, headerValue);
29546 this.xhr.onload = function()
29548 _this.xhrOnLoad(_this.xhr);
29551 this.xhr.onerror = function()
29553 _this.xhrOnError(_this.xhr);
29556 var formData = new FormData();
29558 formData.append('returnHTML', 'NO');
29561 formData.append('crop', crop);
29564 formData.append(this.paramName, file, file.name);
29571 if(this.fireEvent('prepare', this, formData, options) != false){
29573 if(options.manually){
29577 this.xhr.send(formData);
29581 this.uploadCancel();
29584 uploadCancel : function()
29590 this.delegates = [];
29592 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29599 renderPreview : function(file)
29601 if(typeof(file.target) != 'undefined' && file.target){
29605 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29607 var previewEl = this.managerEl.createChild({
29609 cls : 'roo-document-manager-preview',
29613 tooltip : file[this.toolTipName],
29614 cls : 'roo-document-manager-thumb',
29615 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29620 html : '<i class="fa fa-times-circle"></i>'
29625 var close = previewEl.select('button.close', true).first();
29627 close.on('click', this.onRemove, this, file);
29629 file.target = previewEl;
29631 var image = previewEl.select('img', true).first();
29635 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29637 image.on('click', this.onClick, this, file);
29639 this.fireEvent('previewrendered', this, file);
29645 onPreviewLoad : function(file, image)
29647 if(typeof(file.target) == 'undefined' || !file.target){
29651 var width = image.dom.naturalWidth || image.dom.width;
29652 var height = image.dom.naturalHeight || image.dom.height;
29654 if(!this.previewResize) {
29658 if(width > height){
29659 file.target.addClass('wide');
29663 file.target.addClass('tall');
29668 uploadFromSource : function(file, crop)
29670 this.xhr = new XMLHttpRequest();
29672 this.managerEl.createChild({
29674 cls : 'roo-document-manager-loading',
29678 tooltip : file.name,
29679 cls : 'roo-document-manager-thumb',
29680 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29686 this.xhr.open(this.method, this.url, true);
29689 "Accept": "application/json",
29690 "Cache-Control": "no-cache",
29691 "X-Requested-With": "XMLHttpRequest"
29694 for (var headerName in headers) {
29695 var headerValue = headers[headerName];
29697 this.xhr.setRequestHeader(headerName, headerValue);
29703 this.xhr.onload = function()
29705 _this.xhrOnLoad(_this.xhr);
29708 this.xhr.onerror = function()
29710 _this.xhrOnError(_this.xhr);
29713 var formData = new FormData();
29715 formData.append('returnHTML', 'NO');
29717 formData.append('crop', crop);
29719 if(typeof(file.filename) != 'undefined'){
29720 formData.append('filename', file.filename);
29723 if(typeof(file.mimetype) != 'undefined'){
29724 formData.append('mimetype', file.mimetype);
29729 if(this.fireEvent('prepare', this, formData) != false){
29730 this.xhr.send(formData);
29740 * @class Roo.bootstrap.DocumentViewer
29741 * @extends Roo.bootstrap.Component
29742 * Bootstrap DocumentViewer class
29743 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29744 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29747 * Create a new DocumentViewer
29748 * @param {Object} config The config object
29751 Roo.bootstrap.DocumentViewer = function(config){
29752 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29757 * Fire after initEvent
29758 * @param {Roo.bootstrap.DocumentViewer} this
29764 * @param {Roo.bootstrap.DocumentViewer} this
29769 * Fire after download button
29770 * @param {Roo.bootstrap.DocumentViewer} this
29775 * Fire after trash button
29776 * @param {Roo.bootstrap.DocumentViewer} this
29783 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29785 showDownload : true,
29789 getAutoCreate : function()
29793 cls : 'roo-document-viewer',
29797 cls : 'roo-document-viewer-body',
29801 cls : 'roo-document-viewer-thumb',
29805 cls : 'roo-document-viewer-image'
29813 cls : 'roo-document-viewer-footer',
29816 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29820 cls : 'btn-group roo-document-viewer-download',
29824 cls : 'btn btn-default',
29825 html : '<i class="fa fa-download"></i>'
29831 cls : 'btn-group roo-document-viewer-trash',
29835 cls : 'btn btn-default',
29836 html : '<i class="fa fa-trash"></i>'
29849 initEvents : function()
29851 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29852 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29854 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29855 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29857 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29858 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29860 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29861 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29863 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29864 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29866 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29867 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29869 this.bodyEl.on('click', this.onClick, this);
29870 this.downloadBtn.on('click', this.onDownload, this);
29871 this.trashBtn.on('click', this.onTrash, this);
29873 this.downloadBtn.hide();
29874 this.trashBtn.hide();
29876 if(this.showDownload){
29877 this.downloadBtn.show();
29880 if(this.showTrash){
29881 this.trashBtn.show();
29884 if(!this.showDownload && !this.showTrash) {
29885 this.footerEl.hide();
29890 initial : function()
29892 this.fireEvent('initial', this);
29896 onClick : function(e)
29898 e.preventDefault();
29900 this.fireEvent('click', this);
29903 onDownload : function(e)
29905 e.preventDefault();
29907 this.fireEvent('download', this);
29910 onTrash : function(e)
29912 e.preventDefault();
29914 this.fireEvent('trash', this);
29926 * @class Roo.bootstrap.NavProgressBar
29927 * @extends Roo.bootstrap.Component
29928 * Bootstrap NavProgressBar class
29931 * Create a new nav progress bar
29932 * @param {Object} config The config object
29935 Roo.bootstrap.NavProgressBar = function(config){
29936 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29938 this.bullets = this.bullets || [];
29940 // Roo.bootstrap.NavProgressBar.register(this);
29944 * Fires when the active item changes
29945 * @param {Roo.bootstrap.NavProgressBar} this
29946 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29947 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29954 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29959 getAutoCreate : function()
29961 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29965 cls : 'roo-navigation-bar-group',
29969 cls : 'roo-navigation-top-bar'
29973 cls : 'roo-navigation-bullets-bar',
29977 cls : 'roo-navigation-bar'
29984 cls : 'roo-navigation-bottom-bar'
29994 initEvents: function()
29999 onRender : function(ct, position)
30001 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30003 if(this.bullets.length){
30004 Roo.each(this.bullets, function(b){
30013 addItem : function(cfg)
30015 var item = new Roo.bootstrap.NavProgressItem(cfg);
30017 item.parentId = this.id;
30018 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30021 var top = new Roo.bootstrap.Element({
30023 cls : 'roo-navigation-bar-text'
30026 var bottom = new Roo.bootstrap.Element({
30028 cls : 'roo-navigation-bar-text'
30031 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30032 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30034 var topText = new Roo.bootstrap.Element({
30036 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30039 var bottomText = new Roo.bootstrap.Element({
30041 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30044 topText.onRender(top.el, null);
30045 bottomText.onRender(bottom.el, null);
30048 item.bottomEl = bottom;
30051 this.barItems.push(item);
30056 getActive : function()
30058 var active = false;
30060 Roo.each(this.barItems, function(v){
30062 if (!v.isActive()) {
30074 setActiveItem : function(item)
30078 Roo.each(this.barItems, function(v){
30079 if (v.rid == item.rid) {
30083 if (v.isActive()) {
30084 v.setActive(false);
30089 item.setActive(true);
30091 this.fireEvent('changed', this, item, prev);
30094 getBarItem: function(rid)
30098 Roo.each(this.barItems, function(e) {
30099 if (e.rid != rid) {
30110 indexOfItem : function(item)
30114 Roo.each(this.barItems, function(v, i){
30116 if (v.rid != item.rid) {
30127 setActiveNext : function()
30129 var i = this.indexOfItem(this.getActive());
30131 if (i > this.barItems.length) {
30135 this.setActiveItem(this.barItems[i+1]);
30138 setActivePrev : function()
30140 var i = this.indexOfItem(this.getActive());
30146 this.setActiveItem(this.barItems[i-1]);
30149 format : function()
30151 if(!this.barItems.length){
30155 var width = 100 / this.barItems.length;
30157 Roo.each(this.barItems, function(i){
30158 i.el.setStyle('width', width + '%');
30159 i.topEl.el.setStyle('width', width + '%');
30160 i.bottomEl.el.setStyle('width', width + '%');
30169 * Nav Progress Item
30174 * @class Roo.bootstrap.NavProgressItem
30175 * @extends Roo.bootstrap.Component
30176 * Bootstrap NavProgressItem class
30177 * @cfg {String} rid the reference id
30178 * @cfg {Boolean} active (true|false) Is item active default false
30179 * @cfg {Boolean} disabled (true|false) Is item active default false
30180 * @cfg {String} html
30181 * @cfg {String} position (top|bottom) text position default bottom
30182 * @cfg {String} icon show icon instead of number
30185 * Create a new NavProgressItem
30186 * @param {Object} config The config object
30188 Roo.bootstrap.NavProgressItem = function(config){
30189 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30194 * The raw click event for the entire grid.
30195 * @param {Roo.bootstrap.NavProgressItem} this
30196 * @param {Roo.EventObject} e
30203 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30209 position : 'bottom',
30212 getAutoCreate : function()
30214 var iconCls = 'roo-navigation-bar-item-icon';
30216 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30220 cls: 'roo-navigation-bar-item',
30230 cfg.cls += ' active';
30233 cfg.cls += ' disabled';
30239 disable : function()
30241 this.setDisabled(true);
30244 enable : function()
30246 this.setDisabled(false);
30249 initEvents: function()
30251 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30253 this.iconEl.on('click', this.onClick, this);
30256 onClick : function(e)
30258 e.preventDefault();
30264 if(this.fireEvent('click', this, e) === false){
30268 this.parent().setActiveItem(this);
30271 isActive: function ()
30273 return this.active;
30276 setActive : function(state)
30278 if(this.active == state){
30282 this.active = state;
30285 this.el.addClass('active');
30289 this.el.removeClass('active');
30294 setDisabled : function(state)
30296 if(this.disabled == state){
30300 this.disabled = state;
30303 this.el.addClass('disabled');
30307 this.el.removeClass('disabled');
30310 tooltipEl : function()
30312 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30325 * @class Roo.bootstrap.FieldLabel
30326 * @extends Roo.bootstrap.Component
30327 * Bootstrap FieldLabel class
30328 * @cfg {String} html contents of the element
30329 * @cfg {String} tag tag of the element default label
30330 * @cfg {String} cls class of the element
30331 * @cfg {String} target label target
30332 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30333 * @cfg {String} invalidClass default "text-warning"
30334 * @cfg {String} validClass default "text-success"
30335 * @cfg {String} iconTooltip default "This field is required"
30336 * @cfg {String} indicatorpos (left|right) default left
30339 * Create a new FieldLabel
30340 * @param {Object} config The config object
30343 Roo.bootstrap.FieldLabel = function(config){
30344 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30349 * Fires after the field has been marked as invalid.
30350 * @param {Roo.form.FieldLabel} this
30351 * @param {String} msg The validation message
30356 * Fires after the field has been validated with no errors.
30357 * @param {Roo.form.FieldLabel} this
30363 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30370 invalidClass : 'has-warning',
30371 validClass : 'has-success',
30372 iconTooltip : 'This field is required',
30373 indicatorpos : 'left',
30375 getAutoCreate : function(){
30378 if (!this.allowBlank) {
30384 cls : 'roo-bootstrap-field-label ' + this.cls,
30389 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30390 tooltip : this.iconTooltip
30399 if(this.indicatorpos == 'right'){
30402 cls : 'roo-bootstrap-field-label ' + this.cls,
30411 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30412 tooltip : this.iconTooltip
30421 initEvents: function()
30423 Roo.bootstrap.Element.superclass.initEvents.call(this);
30425 this.indicator = this.indicatorEl();
30427 if(this.indicator){
30428 this.indicator.removeClass('visible');
30429 this.indicator.addClass('invisible');
30432 Roo.bootstrap.FieldLabel.register(this);
30435 indicatorEl : function()
30437 var indicator = this.el.select('i.roo-required-indicator',true).first();
30448 * Mark this field as valid
30450 markValid : function()
30452 if(this.indicator){
30453 this.indicator.removeClass('visible');
30454 this.indicator.addClass('invisible');
30457 this.el.removeClass(this.invalidClass);
30459 this.el.addClass(this.validClass);
30461 this.fireEvent('valid', this);
30465 * Mark this field as invalid
30466 * @param {String} msg The validation message
30468 markInvalid : function(msg)
30470 if(this.indicator){
30471 this.indicator.removeClass('invisible');
30472 this.indicator.addClass('visible');
30475 this.el.removeClass(this.validClass);
30477 this.el.addClass(this.invalidClass);
30479 this.fireEvent('invalid', this, msg);
30485 Roo.apply(Roo.bootstrap.FieldLabel, {
30490 * register a FieldLabel Group
30491 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30493 register : function(label)
30495 if(this.groups.hasOwnProperty(label.target)){
30499 this.groups[label.target] = label;
30503 * fetch a FieldLabel Group based on the target
30504 * @param {string} target
30505 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30507 get: function(target) {
30508 if (typeof(this.groups[target]) == 'undefined') {
30512 return this.groups[target] ;
30521 * page DateSplitField.
30527 * @class Roo.bootstrap.DateSplitField
30528 * @extends Roo.bootstrap.Component
30529 * Bootstrap DateSplitField class
30530 * @cfg {string} fieldLabel - the label associated
30531 * @cfg {Number} labelWidth set the width of label (0-12)
30532 * @cfg {String} labelAlign (top|left)
30533 * @cfg {Boolean} dayAllowBlank (true|false) default false
30534 * @cfg {Boolean} monthAllowBlank (true|false) default false
30535 * @cfg {Boolean} yearAllowBlank (true|false) default false
30536 * @cfg {string} dayPlaceholder
30537 * @cfg {string} monthPlaceholder
30538 * @cfg {string} yearPlaceholder
30539 * @cfg {string} dayFormat default 'd'
30540 * @cfg {string} monthFormat default 'm'
30541 * @cfg {string} yearFormat default 'Y'
30542 * @cfg {Number} labellg set the width of label (1-12)
30543 * @cfg {Number} labelmd set the width of label (1-12)
30544 * @cfg {Number} labelsm set the width of label (1-12)
30545 * @cfg {Number} labelxs set the width of label (1-12)
30549 * Create a new DateSplitField
30550 * @param {Object} config The config object
30553 Roo.bootstrap.DateSplitField = function(config){
30554 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30560 * getting the data of years
30561 * @param {Roo.bootstrap.DateSplitField} this
30562 * @param {Object} years
30567 * getting the data of days
30568 * @param {Roo.bootstrap.DateSplitField} this
30569 * @param {Object} days
30574 * Fires after the field has been marked as invalid.
30575 * @param {Roo.form.Field} this
30576 * @param {String} msg The validation message
30581 * Fires after the field has been validated with no errors.
30582 * @param {Roo.form.Field} this
30588 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30591 labelAlign : 'top',
30593 dayAllowBlank : false,
30594 monthAllowBlank : false,
30595 yearAllowBlank : false,
30596 dayPlaceholder : '',
30597 monthPlaceholder : '',
30598 yearPlaceholder : '',
30602 isFormField : true,
30608 getAutoCreate : function()
30612 cls : 'row roo-date-split-field-group',
30617 cls : 'form-hidden-field roo-date-split-field-group-value',
30623 var labelCls = 'col-md-12';
30624 var contentCls = 'col-md-4';
30626 if(this.fieldLabel){
30630 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30634 html : this.fieldLabel
30639 if(this.labelAlign == 'left'){
30641 if(this.labelWidth > 12){
30642 label.style = "width: " + this.labelWidth + 'px';
30645 if(this.labelWidth < 13 && this.labelmd == 0){
30646 this.labelmd = this.labelWidth;
30649 if(this.labellg > 0){
30650 labelCls = ' col-lg-' + this.labellg;
30651 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30654 if(this.labelmd > 0){
30655 labelCls = ' col-md-' + this.labelmd;
30656 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30659 if(this.labelsm > 0){
30660 labelCls = ' col-sm-' + this.labelsm;
30661 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30664 if(this.labelxs > 0){
30665 labelCls = ' col-xs-' + this.labelxs;
30666 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30670 label.cls += ' ' + labelCls;
30672 cfg.cn.push(label);
30675 Roo.each(['day', 'month', 'year'], function(t){
30678 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30685 inputEl: function ()
30687 return this.el.select('.roo-date-split-field-group-value', true).first();
30690 onRender : function(ct, position)
30694 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30696 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30698 this.dayField = new Roo.bootstrap.ComboBox({
30699 allowBlank : this.dayAllowBlank,
30700 alwaysQuery : true,
30701 displayField : 'value',
30704 forceSelection : true,
30706 placeholder : this.dayPlaceholder,
30707 selectOnFocus : true,
30708 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30709 triggerAction : 'all',
30711 valueField : 'value',
30712 store : new Roo.data.SimpleStore({
30713 data : (function() {
30715 _this.fireEvent('days', _this, days);
30718 fields : [ 'value' ]
30721 select : function (_self, record, index)
30723 _this.setValue(_this.getValue());
30728 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30730 this.monthField = new Roo.bootstrap.MonthField({
30731 after : '<i class=\"fa fa-calendar\"></i>',
30732 allowBlank : this.monthAllowBlank,
30733 placeholder : this.monthPlaceholder,
30736 render : function (_self)
30738 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30739 e.preventDefault();
30743 select : function (_self, oldvalue, newvalue)
30745 _this.setValue(_this.getValue());
30750 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30752 this.yearField = new Roo.bootstrap.ComboBox({
30753 allowBlank : this.yearAllowBlank,
30754 alwaysQuery : true,
30755 displayField : 'value',
30758 forceSelection : true,
30760 placeholder : this.yearPlaceholder,
30761 selectOnFocus : true,
30762 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30763 triggerAction : 'all',
30765 valueField : 'value',
30766 store : new Roo.data.SimpleStore({
30767 data : (function() {
30769 _this.fireEvent('years', _this, years);
30772 fields : [ 'value' ]
30775 select : function (_self, record, index)
30777 _this.setValue(_this.getValue());
30782 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30785 setValue : function(v, format)
30787 this.inputEl.dom.value = v;
30789 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30791 var d = Date.parseDate(v, f);
30798 this.setDay(d.format(this.dayFormat));
30799 this.setMonth(d.format(this.monthFormat));
30800 this.setYear(d.format(this.yearFormat));
30807 setDay : function(v)
30809 this.dayField.setValue(v);
30810 this.inputEl.dom.value = this.getValue();
30815 setMonth : function(v)
30817 this.monthField.setValue(v, true);
30818 this.inputEl.dom.value = this.getValue();
30823 setYear : function(v)
30825 this.yearField.setValue(v);
30826 this.inputEl.dom.value = this.getValue();
30831 getDay : function()
30833 return this.dayField.getValue();
30836 getMonth : function()
30838 return this.monthField.getValue();
30841 getYear : function()
30843 return this.yearField.getValue();
30846 getValue : function()
30848 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30850 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30860 this.inputEl.dom.value = '';
30865 validate : function()
30867 var d = this.dayField.validate();
30868 var m = this.monthField.validate();
30869 var y = this.yearField.validate();
30874 (!this.dayAllowBlank && !d) ||
30875 (!this.monthAllowBlank && !m) ||
30876 (!this.yearAllowBlank && !y)
30881 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30890 this.markInvalid();
30895 markValid : function()
30898 var label = this.el.select('label', true).first();
30899 var icon = this.el.select('i.fa-star', true).first();
30905 this.fireEvent('valid', this);
30909 * Mark this field as invalid
30910 * @param {String} msg The validation message
30912 markInvalid : function(msg)
30915 var label = this.el.select('label', true).first();
30916 var icon = this.el.select('i.fa-star', true).first();
30918 if(label && !icon){
30919 this.el.select('.roo-date-split-field-label', true).createChild({
30921 cls : 'text-danger fa fa-lg fa-star',
30922 tooltip : 'This field is required',
30923 style : 'margin-right:5px;'
30927 this.fireEvent('invalid', this, msg);
30930 clearInvalid : function()
30932 var label = this.el.select('label', true).first();
30933 var icon = this.el.select('i.fa-star', true).first();
30939 this.fireEvent('valid', this);
30942 getName: function()
30952 * http://masonry.desandro.com
30954 * The idea is to render all the bricks based on vertical width...
30956 * The original code extends 'outlayer' - we might need to use that....
30962 * @class Roo.bootstrap.LayoutMasonry
30963 * @extends Roo.bootstrap.Component
30964 * Bootstrap Layout Masonry class
30967 * Create a new Element
30968 * @param {Object} config The config object
30971 Roo.bootstrap.LayoutMasonry = function(config){
30973 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30977 Roo.bootstrap.LayoutMasonry.register(this);
30983 * Fire after layout the items
30984 * @param {Roo.bootstrap.LayoutMasonry} this
30985 * @param {Roo.EventObject} e
30992 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30995 * @cfg {Boolean} isLayoutInstant = no animation?
30997 isLayoutInstant : false, // needed?
31000 * @cfg {Number} boxWidth width of the columns
31005 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31010 * @cfg {Number} padWidth padding below box..
31015 * @cfg {Number} gutter gutter width..
31020 * @cfg {Number} maxCols maximum number of columns
31026 * @cfg {Boolean} isAutoInitial defalut true
31028 isAutoInitial : true,
31033 * @cfg {Boolean} isHorizontal defalut false
31035 isHorizontal : false,
31037 currentSize : null,
31043 bricks: null, //CompositeElement
31047 _isLayoutInited : false,
31049 // isAlternative : false, // only use for vertical layout...
31052 * @cfg {Number} alternativePadWidth padding below box..
31054 alternativePadWidth : 50,
31056 selectedBrick : [],
31058 getAutoCreate : function(){
31060 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31064 cls: 'blog-masonary-wrapper ' + this.cls,
31066 cls : 'mas-boxes masonary'
31073 getChildContainer: function( )
31075 if (this.boxesEl) {
31076 return this.boxesEl;
31079 this.boxesEl = this.el.select('.mas-boxes').first();
31081 return this.boxesEl;
31085 initEvents : function()
31089 if(this.isAutoInitial){
31090 Roo.log('hook children rendered');
31091 this.on('childrenrendered', function() {
31092 Roo.log('children rendered');
31098 initial : function()
31100 this.selectedBrick = [];
31102 this.currentSize = this.el.getBox(true);
31104 Roo.EventManager.onWindowResize(this.resize, this);
31106 if(!this.isAutoInitial){
31114 //this.layout.defer(500,this);
31118 resize : function()
31120 var cs = this.el.getBox(true);
31123 this.currentSize.width == cs.width &&
31124 this.currentSize.x == cs.x &&
31125 this.currentSize.height == cs.height &&
31126 this.currentSize.y == cs.y
31128 Roo.log("no change in with or X or Y");
31132 this.currentSize = cs;
31138 layout : function()
31140 this._resetLayout();
31142 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31144 this.layoutItems( isInstant );
31146 this._isLayoutInited = true;
31148 this.fireEvent('layout', this);
31152 _resetLayout : function()
31154 if(this.isHorizontal){
31155 this.horizontalMeasureColumns();
31159 this.verticalMeasureColumns();
31163 verticalMeasureColumns : function()
31165 this.getContainerWidth();
31167 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31168 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31172 var boxWidth = this.boxWidth + this.padWidth;
31174 if(this.containerWidth < this.boxWidth){
31175 boxWidth = this.containerWidth
31178 var containerWidth = this.containerWidth;
31180 var cols = Math.floor(containerWidth / boxWidth);
31182 this.cols = Math.max( cols, 1 );
31184 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31186 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31188 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31190 this.colWidth = boxWidth + avail - this.padWidth;
31192 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31193 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31196 horizontalMeasureColumns : function()
31198 this.getContainerWidth();
31200 var boxWidth = this.boxWidth;
31202 if(this.containerWidth < boxWidth){
31203 boxWidth = this.containerWidth;
31206 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31208 this.el.setHeight(boxWidth);
31212 getContainerWidth : function()
31214 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31217 layoutItems : function( isInstant )
31219 Roo.log(this.bricks);
31221 var items = Roo.apply([], this.bricks);
31223 if(this.isHorizontal){
31224 this._horizontalLayoutItems( items , isInstant );
31228 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31229 // this._verticalAlternativeLayoutItems( items , isInstant );
31233 this._verticalLayoutItems( items , isInstant );
31237 _verticalLayoutItems : function ( items , isInstant)
31239 if ( !items || !items.length ) {
31244 ['xs', 'xs', 'xs', 'tall'],
31245 ['xs', 'xs', 'tall'],
31246 ['xs', 'xs', 'sm'],
31247 ['xs', 'xs', 'xs'],
31253 ['sm', 'xs', 'xs'],
31257 ['tall', 'xs', 'xs', 'xs'],
31258 ['tall', 'xs', 'xs'],
31270 Roo.each(items, function(item, k){
31272 switch (item.size) {
31273 // these layouts take up a full box,
31284 boxes.push([item]);
31307 var filterPattern = function(box, length)
31315 var pattern = box.slice(0, length);
31319 Roo.each(pattern, function(i){
31320 format.push(i.size);
31323 Roo.each(standard, function(s){
31325 if(String(s) != String(format)){
31334 if(!match && length == 1){
31339 filterPattern(box, length - 1);
31343 queue.push(pattern);
31345 box = box.slice(length, box.length);
31347 filterPattern(box, 4);
31353 Roo.each(boxes, function(box, k){
31359 if(box.length == 1){
31364 filterPattern(box, 4);
31368 this._processVerticalLayoutQueue( queue, isInstant );
31372 // _verticalAlternativeLayoutItems : function( items , isInstant )
31374 // if ( !items || !items.length ) {
31378 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31382 _horizontalLayoutItems : function ( items , isInstant)
31384 if ( !items || !items.length || items.length < 3) {
31390 var eItems = items.slice(0, 3);
31392 items = items.slice(3, items.length);
31395 ['xs', 'xs', 'xs', 'wide'],
31396 ['xs', 'xs', 'wide'],
31397 ['xs', 'xs', 'sm'],
31398 ['xs', 'xs', 'xs'],
31404 ['sm', 'xs', 'xs'],
31408 ['wide', 'xs', 'xs', 'xs'],
31409 ['wide', 'xs', 'xs'],
31422 Roo.each(items, function(item, k){
31424 switch (item.size) {
31435 boxes.push([item]);
31459 var filterPattern = function(box, length)
31467 var pattern = box.slice(0, length);
31471 Roo.each(pattern, function(i){
31472 format.push(i.size);
31475 Roo.each(standard, function(s){
31477 if(String(s) != String(format)){
31486 if(!match && length == 1){
31491 filterPattern(box, length - 1);
31495 queue.push(pattern);
31497 box = box.slice(length, box.length);
31499 filterPattern(box, 4);
31505 Roo.each(boxes, function(box, k){
31511 if(box.length == 1){
31516 filterPattern(box, 4);
31523 var pos = this.el.getBox(true);
31527 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31529 var hit_end = false;
31531 Roo.each(queue, function(box){
31535 Roo.each(box, function(b){
31537 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31547 Roo.each(box, function(b){
31549 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31552 mx = Math.max(mx, b.x);
31556 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31560 Roo.each(box, function(b){
31562 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31576 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31579 /** Sets position of item in DOM
31580 * @param {Element} item
31581 * @param {Number} x - horizontal position
31582 * @param {Number} y - vertical position
31583 * @param {Boolean} isInstant - disables transitions
31585 _processVerticalLayoutQueue : function( queue, isInstant )
31587 var pos = this.el.getBox(true);
31592 for (var i = 0; i < this.cols; i++){
31596 Roo.each(queue, function(box, k){
31598 var col = k % this.cols;
31600 Roo.each(box, function(b,kk){
31602 b.el.position('absolute');
31604 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31605 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31607 if(b.size == 'md-left' || b.size == 'md-right'){
31608 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31609 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31612 b.el.setWidth(width);
31613 b.el.setHeight(height);
31615 b.el.select('iframe',true).setSize(width,height);
31619 for (var i = 0; i < this.cols; i++){
31621 if(maxY[i] < maxY[col]){
31626 col = Math.min(col, i);
31630 x = pos.x + col * (this.colWidth + this.padWidth);
31634 var positions = [];
31636 switch (box.length){
31638 positions = this.getVerticalOneBoxColPositions(x, y, box);
31641 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31644 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31647 positions = this.getVerticalFourBoxColPositions(x, y, box);
31653 Roo.each(box, function(b,kk){
31655 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31657 var sz = b.el.getSize();
31659 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31667 for (var i = 0; i < this.cols; i++){
31668 mY = Math.max(mY, maxY[i]);
31671 this.el.setHeight(mY - pos.y);
31675 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31677 // var pos = this.el.getBox(true);
31680 // var maxX = pos.right;
31682 // var maxHeight = 0;
31684 // Roo.each(items, function(item, k){
31688 // item.el.position('absolute');
31690 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31692 // item.el.setWidth(width);
31694 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31696 // item.el.setHeight(height);
31699 // item.el.setXY([x, y], isInstant ? false : true);
31701 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31704 // y = y + height + this.alternativePadWidth;
31706 // maxHeight = maxHeight + height + this.alternativePadWidth;
31710 // this.el.setHeight(maxHeight);
31714 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31716 var pos = this.el.getBox(true);
31721 var maxX = pos.right;
31723 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31725 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31727 Roo.each(queue, function(box, k){
31729 Roo.each(box, function(b, kk){
31731 b.el.position('absolute');
31733 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31734 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31736 if(b.size == 'md-left' || b.size == 'md-right'){
31737 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31738 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31741 b.el.setWidth(width);
31742 b.el.setHeight(height);
31750 var positions = [];
31752 switch (box.length){
31754 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31757 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31760 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31763 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31769 Roo.each(box, function(b,kk){
31771 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31773 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31781 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31783 Roo.each(eItems, function(b,k){
31785 b.size = (k == 0) ? 'sm' : 'xs';
31786 b.x = (k == 0) ? 2 : 1;
31787 b.y = (k == 0) ? 2 : 1;
31789 b.el.position('absolute');
31791 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31793 b.el.setWidth(width);
31795 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31797 b.el.setHeight(height);
31801 var positions = [];
31804 x : maxX - this.unitWidth * 2 - this.gutter,
31809 x : maxX - this.unitWidth,
31810 y : minY + (this.unitWidth + this.gutter) * 2
31814 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31818 Roo.each(eItems, function(b,k){
31820 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31826 getVerticalOneBoxColPositions : function(x, y, box)
31830 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31832 if(box[0].size == 'md-left'){
31836 if(box[0].size == 'md-right'){
31841 x : x + (this.unitWidth + this.gutter) * rand,
31848 getVerticalTwoBoxColPositions : function(x, y, box)
31852 if(box[0].size == 'xs'){
31856 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31860 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31874 x : x + (this.unitWidth + this.gutter) * 2,
31875 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31882 getVerticalThreeBoxColPositions : function(x, y, box)
31886 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31894 x : x + (this.unitWidth + this.gutter) * 1,
31899 x : x + (this.unitWidth + this.gutter) * 2,
31907 if(box[0].size == 'xs' && box[1].size == 'xs'){
31916 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31920 x : x + (this.unitWidth + this.gutter) * 1,
31934 x : x + (this.unitWidth + this.gutter) * 2,
31939 x : x + (this.unitWidth + this.gutter) * 2,
31940 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31947 getVerticalFourBoxColPositions : function(x, y, box)
31951 if(box[0].size == 'xs'){
31960 y : y + (this.unitHeight + this.gutter) * 1
31965 y : y + (this.unitHeight + this.gutter) * 2
31969 x : x + (this.unitWidth + this.gutter) * 1,
31983 x : x + (this.unitWidth + this.gutter) * 2,
31988 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31989 y : y + (this.unitHeight + this.gutter) * 1
31993 x : x + (this.unitWidth + this.gutter) * 2,
31994 y : y + (this.unitWidth + this.gutter) * 2
32001 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32005 if(box[0].size == 'md-left'){
32007 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32014 if(box[0].size == 'md-right'){
32016 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32017 y : minY + (this.unitWidth + this.gutter) * 1
32023 var rand = Math.floor(Math.random() * (4 - box[0].y));
32026 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32027 y : minY + (this.unitWidth + this.gutter) * rand
32034 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32038 if(box[0].size == 'xs'){
32041 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32046 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32047 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32055 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32060 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32061 y : minY + (this.unitWidth + this.gutter) * 2
32068 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32072 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32075 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32080 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32081 y : minY + (this.unitWidth + this.gutter) * 1
32085 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32086 y : minY + (this.unitWidth + this.gutter) * 2
32093 if(box[0].size == 'xs' && box[1].size == 'xs'){
32096 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32101 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32106 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32107 y : minY + (this.unitWidth + this.gutter) * 1
32115 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32120 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32121 y : minY + (this.unitWidth + this.gutter) * 2
32125 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32126 y : minY + (this.unitWidth + this.gutter) * 2
32133 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32137 if(box[0].size == 'xs'){
32140 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32145 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32150 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),
32155 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32156 y : minY + (this.unitWidth + this.gutter) * 1
32164 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32169 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32170 y : minY + (this.unitWidth + this.gutter) * 2
32174 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32175 y : minY + (this.unitWidth + this.gutter) * 2
32179 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),
32180 y : minY + (this.unitWidth + this.gutter) * 2
32188 * remove a Masonry Brick
32189 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32191 removeBrick : function(brick_id)
32197 for (var i = 0; i<this.bricks.length; i++) {
32198 if (this.bricks[i].id == brick_id) {
32199 this.bricks.splice(i,1);
32200 this.el.dom.removeChild(Roo.get(brick_id).dom);
32207 * adds a Masonry Brick
32208 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32210 addBrick : function(cfg)
32212 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32213 //this.register(cn);
32214 cn.parentId = this.id;
32215 cn.render(this.el);
32220 * register a Masonry Brick
32221 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32224 register : function(brick)
32226 this.bricks.push(brick);
32227 brick.masonryId = this.id;
32231 * clear all the Masonry Brick
32233 clearAll : function()
32236 //this.getChildContainer().dom.innerHTML = "";
32237 this.el.dom.innerHTML = '';
32240 getSelected : function()
32242 if (!this.selectedBrick) {
32246 return this.selectedBrick;
32250 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32254 * register a Masonry Layout
32255 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32258 register : function(layout)
32260 this.groups[layout.id] = layout;
32263 * fetch a Masonry Layout based on the masonry layout ID
32264 * @param {string} the masonry layout to add
32265 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32268 get: function(layout_id) {
32269 if (typeof(this.groups[layout_id]) == 'undefined') {
32272 return this.groups[layout_id] ;
32284 * http://masonry.desandro.com
32286 * The idea is to render all the bricks based on vertical width...
32288 * The original code extends 'outlayer' - we might need to use that....
32294 * @class Roo.bootstrap.LayoutMasonryAuto
32295 * @extends Roo.bootstrap.Component
32296 * Bootstrap Layout Masonry class
32299 * Create a new Element
32300 * @param {Object} config The config object
32303 Roo.bootstrap.LayoutMasonryAuto = function(config){
32304 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32307 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32310 * @cfg {Boolean} isFitWidth - resize the width..
32312 isFitWidth : false, // options..
32314 * @cfg {Boolean} isOriginLeft = left align?
32316 isOriginLeft : true,
32318 * @cfg {Boolean} isOriginTop = top align?
32320 isOriginTop : false,
32322 * @cfg {Boolean} isLayoutInstant = no animation?
32324 isLayoutInstant : false, // needed?
32326 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32328 isResizingContainer : true,
32330 * @cfg {Number} columnWidth width of the columns
32336 * @cfg {Number} maxCols maximum number of columns
32341 * @cfg {Number} padHeight padding below box..
32347 * @cfg {Boolean} isAutoInitial defalut true
32350 isAutoInitial : true,
32356 initialColumnWidth : 0,
32357 currentSize : null,
32359 colYs : null, // array.
32366 bricks: null, //CompositeElement
32367 cols : 0, // array?
32368 // element : null, // wrapped now this.el
32369 _isLayoutInited : null,
32372 getAutoCreate : function(){
32376 cls: 'blog-masonary-wrapper ' + this.cls,
32378 cls : 'mas-boxes masonary'
32385 getChildContainer: function( )
32387 if (this.boxesEl) {
32388 return this.boxesEl;
32391 this.boxesEl = this.el.select('.mas-boxes').first();
32393 return this.boxesEl;
32397 initEvents : function()
32401 if(this.isAutoInitial){
32402 Roo.log('hook children rendered');
32403 this.on('childrenrendered', function() {
32404 Roo.log('children rendered');
32411 initial : function()
32413 this.reloadItems();
32415 this.currentSize = this.el.getBox(true);
32417 /// was window resize... - let's see if this works..
32418 Roo.EventManager.onWindowResize(this.resize, this);
32420 if(!this.isAutoInitial){
32425 this.layout.defer(500,this);
32428 reloadItems: function()
32430 this.bricks = this.el.select('.masonry-brick', true);
32432 this.bricks.each(function(b) {
32433 //Roo.log(b.getSize());
32434 if (!b.attr('originalwidth')) {
32435 b.attr('originalwidth', b.getSize().width);
32440 Roo.log(this.bricks.elements.length);
32443 resize : function()
32446 var cs = this.el.getBox(true);
32448 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32449 Roo.log("no change in with or X");
32452 this.currentSize = cs;
32456 layout : function()
32459 this._resetLayout();
32460 //this._manageStamps();
32462 // don't animate first layout
32463 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32464 this.layoutItems( isInstant );
32466 // flag for initalized
32467 this._isLayoutInited = true;
32470 layoutItems : function( isInstant )
32472 //var items = this._getItemsForLayout( this.items );
32473 // original code supports filtering layout items.. we just ignore it..
32475 this._layoutItems( this.bricks , isInstant );
32477 this._postLayout();
32479 _layoutItems : function ( items , isInstant)
32481 //this.fireEvent( 'layout', this, items );
32484 if ( !items || !items.elements.length ) {
32485 // no items, emit event with empty array
32490 items.each(function(item) {
32491 Roo.log("layout item");
32493 // get x/y object from method
32494 var position = this._getItemLayoutPosition( item );
32496 position.item = item;
32497 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32498 queue.push( position );
32501 this._processLayoutQueue( queue );
32503 /** Sets position of item in DOM
32504 * @param {Element} item
32505 * @param {Number} x - horizontal position
32506 * @param {Number} y - vertical position
32507 * @param {Boolean} isInstant - disables transitions
32509 _processLayoutQueue : function( queue )
32511 for ( var i=0, len = queue.length; i < len; i++ ) {
32512 var obj = queue[i];
32513 obj.item.position('absolute');
32514 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32520 * Any logic you want to do after each layout,
32521 * i.e. size the container
32523 _postLayout : function()
32525 this.resizeContainer();
32528 resizeContainer : function()
32530 if ( !this.isResizingContainer ) {
32533 var size = this._getContainerSize();
32535 this.el.setSize(size.width,size.height);
32536 this.boxesEl.setSize(size.width,size.height);
32542 _resetLayout : function()
32544 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32545 this.colWidth = this.el.getWidth();
32546 //this.gutter = this.el.getWidth();
32548 this.measureColumns();
32554 this.colYs.push( 0 );
32560 measureColumns : function()
32562 this.getContainerWidth();
32563 // if columnWidth is 0, default to outerWidth of first item
32564 if ( !this.columnWidth ) {
32565 var firstItem = this.bricks.first();
32566 Roo.log(firstItem);
32567 this.columnWidth = this.containerWidth;
32568 if (firstItem && firstItem.attr('originalwidth') ) {
32569 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32571 // columnWidth fall back to item of first element
32572 Roo.log("set column width?");
32573 this.initialColumnWidth = this.columnWidth ;
32575 // if first elem has no width, default to size of container
32580 if (this.initialColumnWidth) {
32581 this.columnWidth = this.initialColumnWidth;
32586 // column width is fixed at the top - however if container width get's smaller we should
32589 // this bit calcs how man columns..
32591 var columnWidth = this.columnWidth += this.gutter;
32593 // calculate columns
32594 var containerWidth = this.containerWidth + this.gutter;
32596 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32597 // fix rounding errors, typically with gutters
32598 var excess = columnWidth - containerWidth % columnWidth;
32601 // if overshoot is less than a pixel, round up, otherwise floor it
32602 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32603 cols = Math[ mathMethod ]( cols );
32604 this.cols = Math.max( cols, 1 );
32605 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32607 // padding positioning..
32608 var totalColWidth = this.cols * this.columnWidth;
32609 var padavail = this.containerWidth - totalColWidth;
32610 // so for 2 columns - we need 3 'pads'
32612 var padNeeded = (1+this.cols) * this.padWidth;
32614 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32616 this.columnWidth += padExtra
32617 //this.padWidth = Math.floor(padavail / ( this.cols));
32619 // adjust colum width so that padding is fixed??
32621 // we have 3 columns ... total = width * 3
32622 // we have X left over... that should be used by
32624 //if (this.expandC) {
32632 getContainerWidth : function()
32634 /* // container is parent if fit width
32635 var container = this.isFitWidth ? this.element.parentNode : this.element;
32636 // check that this.size and size are there
32637 // IE8 triggers resize on body size change, so they might not be
32639 var size = getSize( container ); //FIXME
32640 this.containerWidth = size && size.innerWidth; //FIXME
32643 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32647 _getItemLayoutPosition : function( item ) // what is item?
32649 // we resize the item to our columnWidth..
32651 item.setWidth(this.columnWidth);
32652 item.autoBoxAdjust = false;
32654 var sz = item.getSize();
32656 // how many columns does this brick span
32657 var remainder = this.containerWidth % this.columnWidth;
32659 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32660 // round if off by 1 pixel, otherwise use ceil
32661 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32662 colSpan = Math.min( colSpan, this.cols );
32664 // normally this should be '1' as we dont' currently allow multi width columns..
32666 var colGroup = this._getColGroup( colSpan );
32667 // get the minimum Y value from the columns
32668 var minimumY = Math.min.apply( Math, colGroup );
32669 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32671 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32673 // position the brick
32675 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32676 y: this.currentSize.y + minimumY + this.padHeight
32680 // apply setHeight to necessary columns
32681 var setHeight = minimumY + sz.height + this.padHeight;
32682 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32684 var setSpan = this.cols + 1 - colGroup.length;
32685 for ( var i = 0; i < setSpan; i++ ) {
32686 this.colYs[ shortColIndex + i ] = setHeight ;
32693 * @param {Number} colSpan - number of columns the element spans
32694 * @returns {Array} colGroup
32696 _getColGroup : function( colSpan )
32698 if ( colSpan < 2 ) {
32699 // if brick spans only one column, use all the column Ys
32704 // how many different places could this brick fit horizontally
32705 var groupCount = this.cols + 1 - colSpan;
32706 // for each group potential horizontal position
32707 for ( var i = 0; i < groupCount; i++ ) {
32708 // make an array of colY values for that one group
32709 var groupColYs = this.colYs.slice( i, i + colSpan );
32710 // and get the max value of the array
32711 colGroup[i] = Math.max.apply( Math, groupColYs );
32716 _manageStamp : function( stamp )
32718 var stampSize = stamp.getSize();
32719 var offset = stamp.getBox();
32720 // get the columns that this stamp affects
32721 var firstX = this.isOriginLeft ? offset.x : offset.right;
32722 var lastX = firstX + stampSize.width;
32723 var firstCol = Math.floor( firstX / this.columnWidth );
32724 firstCol = Math.max( 0, firstCol );
32726 var lastCol = Math.floor( lastX / this.columnWidth );
32727 // lastCol should not go over if multiple of columnWidth #425
32728 lastCol -= lastX % this.columnWidth ? 0 : 1;
32729 lastCol = Math.min( this.cols - 1, lastCol );
32731 // set colYs to bottom of the stamp
32732 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32735 for ( var i = firstCol; i <= lastCol; i++ ) {
32736 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32741 _getContainerSize : function()
32743 this.maxY = Math.max.apply( Math, this.colYs );
32748 if ( this.isFitWidth ) {
32749 size.width = this._getContainerFitWidth();
32755 _getContainerFitWidth : function()
32757 var unusedCols = 0;
32758 // count unused columns
32761 if ( this.colYs[i] !== 0 ) {
32766 // fit container to columns that have been used
32767 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32770 needsResizeLayout : function()
32772 var previousWidth = this.containerWidth;
32773 this.getContainerWidth();
32774 return previousWidth !== this.containerWidth;
32789 * @class Roo.bootstrap.MasonryBrick
32790 * @extends Roo.bootstrap.Component
32791 * Bootstrap MasonryBrick class
32794 * Create a new MasonryBrick
32795 * @param {Object} config The config object
32798 Roo.bootstrap.MasonryBrick = function(config){
32800 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32802 Roo.bootstrap.MasonryBrick.register(this);
32808 * When a MasonryBrick is clcik
32809 * @param {Roo.bootstrap.MasonryBrick} this
32810 * @param {Roo.EventObject} e
32816 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32819 * @cfg {String} title
32823 * @cfg {String} html
32827 * @cfg {String} bgimage
32831 * @cfg {String} videourl
32835 * @cfg {String} cls
32839 * @cfg {String} href
32843 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32848 * @cfg {String} placetitle (center|bottom)
32853 * @cfg {Boolean} isFitContainer defalut true
32855 isFitContainer : true,
32858 * @cfg {Boolean} preventDefault defalut false
32860 preventDefault : false,
32863 * @cfg {Boolean} inverse defalut false
32865 maskInverse : false,
32867 getAutoCreate : function()
32869 if(!this.isFitContainer){
32870 return this.getSplitAutoCreate();
32873 var cls = 'masonry-brick masonry-brick-full';
32875 if(this.href.length){
32876 cls += ' masonry-brick-link';
32879 if(this.bgimage.length){
32880 cls += ' masonry-brick-image';
32883 if(this.maskInverse){
32884 cls += ' mask-inverse';
32887 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32888 cls += ' enable-mask';
32892 cls += ' masonry-' + this.size + '-brick';
32895 if(this.placetitle.length){
32897 switch (this.placetitle) {
32899 cls += ' masonry-center-title';
32902 cls += ' masonry-bottom-title';
32909 if(!this.html.length && !this.bgimage.length){
32910 cls += ' masonry-center-title';
32913 if(!this.html.length && this.bgimage.length){
32914 cls += ' masonry-bottom-title';
32919 cls += ' ' + this.cls;
32923 tag: (this.href.length) ? 'a' : 'div',
32928 cls: 'masonry-brick-mask'
32932 cls: 'masonry-brick-paragraph',
32938 if(this.href.length){
32939 cfg.href = this.href;
32942 var cn = cfg.cn[1].cn;
32944 if(this.title.length){
32947 cls: 'masonry-brick-title',
32952 if(this.html.length){
32955 cls: 'masonry-brick-text',
32960 if (!this.title.length && !this.html.length) {
32961 cfg.cn[1].cls += ' hide';
32964 if(this.bgimage.length){
32967 cls: 'masonry-brick-image-view',
32972 if(this.videourl.length){
32973 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32974 // youtube support only?
32977 cls: 'masonry-brick-image-view',
32980 allowfullscreen : true
32988 getSplitAutoCreate : function()
32990 var cls = 'masonry-brick masonry-brick-split';
32992 if(this.href.length){
32993 cls += ' masonry-brick-link';
32996 if(this.bgimage.length){
32997 cls += ' masonry-brick-image';
33001 cls += ' masonry-' + this.size + '-brick';
33004 switch (this.placetitle) {
33006 cls += ' masonry-center-title';
33009 cls += ' masonry-bottom-title';
33012 if(!this.bgimage.length){
33013 cls += ' masonry-center-title';
33016 if(this.bgimage.length){
33017 cls += ' masonry-bottom-title';
33023 cls += ' ' + this.cls;
33027 tag: (this.href.length) ? 'a' : 'div',
33032 cls: 'masonry-brick-split-head',
33036 cls: 'masonry-brick-paragraph',
33043 cls: 'masonry-brick-split-body',
33049 if(this.href.length){
33050 cfg.href = this.href;
33053 if(this.title.length){
33054 cfg.cn[0].cn[0].cn.push({
33056 cls: 'masonry-brick-title',
33061 if(this.html.length){
33062 cfg.cn[1].cn.push({
33064 cls: 'masonry-brick-text',
33069 if(this.bgimage.length){
33070 cfg.cn[0].cn.push({
33072 cls: 'masonry-brick-image-view',
33077 if(this.videourl.length){
33078 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33079 // youtube support only?
33080 cfg.cn[0].cn.cn.push({
33082 cls: 'masonry-brick-image-view',
33085 allowfullscreen : true
33092 initEvents: function()
33094 switch (this.size) {
33127 this.el.on('touchstart', this.onTouchStart, this);
33128 this.el.on('touchmove', this.onTouchMove, this);
33129 this.el.on('touchend', this.onTouchEnd, this);
33130 this.el.on('contextmenu', this.onContextMenu, this);
33132 this.el.on('mouseenter' ,this.enter, this);
33133 this.el.on('mouseleave', this.leave, this);
33134 this.el.on('click', this.onClick, this);
33137 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33138 this.parent().bricks.push(this);
33143 onClick: function(e, el)
33145 var time = this.endTimer - this.startTimer;
33146 // Roo.log(e.preventDefault());
33149 e.preventDefault();
33154 if(!this.preventDefault){
33158 e.preventDefault();
33160 if (this.activeClass != '') {
33161 this.selectBrick();
33164 this.fireEvent('click', this, e);
33167 enter: function(e, el)
33169 e.preventDefault();
33171 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33175 if(this.bgimage.length && this.html.length){
33176 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33180 leave: function(e, el)
33182 e.preventDefault();
33184 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33188 if(this.bgimage.length && this.html.length){
33189 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33193 onTouchStart: function(e, el)
33195 // e.preventDefault();
33197 this.touchmoved = false;
33199 if(!this.isFitContainer){
33203 if(!this.bgimage.length || !this.html.length){
33207 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33209 this.timer = new Date().getTime();
33213 onTouchMove: function(e, el)
33215 this.touchmoved = true;
33218 onContextMenu : function(e,el)
33220 e.preventDefault();
33221 e.stopPropagation();
33225 onTouchEnd: function(e, el)
33227 // e.preventDefault();
33229 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33236 if(!this.bgimage.length || !this.html.length){
33238 if(this.href.length){
33239 window.location.href = this.href;
33245 if(!this.isFitContainer){
33249 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33251 window.location.href = this.href;
33254 //selection on single brick only
33255 selectBrick : function() {
33257 if (!this.parentId) {
33261 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33262 var index = m.selectedBrick.indexOf(this.id);
33265 m.selectedBrick.splice(index,1);
33266 this.el.removeClass(this.activeClass);
33270 for(var i = 0; i < m.selectedBrick.length; i++) {
33271 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33272 b.el.removeClass(b.activeClass);
33275 m.selectedBrick = [];
33277 m.selectedBrick.push(this.id);
33278 this.el.addClass(this.activeClass);
33282 isSelected : function(){
33283 return this.el.hasClass(this.activeClass);
33288 Roo.apply(Roo.bootstrap.MasonryBrick, {
33291 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33293 * register a Masonry Brick
33294 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33297 register : function(brick)
33299 //this.groups[brick.id] = brick;
33300 this.groups.add(brick.id, brick);
33303 * fetch a masonry brick based on the masonry brick ID
33304 * @param {string} the masonry brick to add
33305 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33308 get: function(brick_id)
33310 // if (typeof(this.groups[brick_id]) == 'undefined') {
33313 // return this.groups[brick_id] ;
33315 if(this.groups.key(brick_id)) {
33316 return this.groups.key(brick_id);
33334 * @class Roo.bootstrap.Brick
33335 * @extends Roo.bootstrap.Component
33336 * Bootstrap Brick class
33339 * Create a new Brick
33340 * @param {Object} config The config object
33343 Roo.bootstrap.Brick = function(config){
33344 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33350 * When a Brick is click
33351 * @param {Roo.bootstrap.Brick} this
33352 * @param {Roo.EventObject} e
33358 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33361 * @cfg {String} title
33365 * @cfg {String} html
33369 * @cfg {String} bgimage
33373 * @cfg {String} cls
33377 * @cfg {String} href
33381 * @cfg {String} video
33385 * @cfg {Boolean} square
33389 getAutoCreate : function()
33391 var cls = 'roo-brick';
33393 if(this.href.length){
33394 cls += ' roo-brick-link';
33397 if(this.bgimage.length){
33398 cls += ' roo-brick-image';
33401 if(!this.html.length && !this.bgimage.length){
33402 cls += ' roo-brick-center-title';
33405 if(!this.html.length && this.bgimage.length){
33406 cls += ' roo-brick-bottom-title';
33410 cls += ' ' + this.cls;
33414 tag: (this.href.length) ? 'a' : 'div',
33419 cls: 'roo-brick-paragraph',
33425 if(this.href.length){
33426 cfg.href = this.href;
33429 var cn = cfg.cn[0].cn;
33431 if(this.title.length){
33434 cls: 'roo-brick-title',
33439 if(this.html.length){
33442 cls: 'roo-brick-text',
33449 if(this.bgimage.length){
33452 cls: 'roo-brick-image-view',
33460 initEvents: function()
33462 if(this.title.length || this.html.length){
33463 this.el.on('mouseenter' ,this.enter, this);
33464 this.el.on('mouseleave', this.leave, this);
33467 Roo.EventManager.onWindowResize(this.resize, this);
33469 if(this.bgimage.length){
33470 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33471 this.imageEl.on('load', this.onImageLoad, this);
33478 onImageLoad : function()
33483 resize : function()
33485 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33487 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33489 if(this.bgimage.length){
33490 var image = this.el.select('.roo-brick-image-view', true).first();
33492 image.setWidth(paragraph.getWidth());
33495 image.setHeight(paragraph.getWidth());
33498 this.el.setHeight(image.getHeight());
33499 paragraph.setHeight(image.getHeight());
33505 enter: function(e, el)
33507 e.preventDefault();
33509 if(this.bgimage.length){
33510 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33511 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33515 leave: function(e, el)
33517 e.preventDefault();
33519 if(this.bgimage.length){
33520 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33521 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33536 * @class Roo.bootstrap.NumberField
33537 * @extends Roo.bootstrap.Input
33538 * Bootstrap NumberField class
33544 * Create a new NumberField
33545 * @param {Object} config The config object
33548 Roo.bootstrap.NumberField = function(config){
33549 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33552 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33555 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33557 allowDecimals : true,
33559 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33561 decimalSeparator : ".",
33563 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33565 decimalPrecision : 2,
33567 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33569 allowNegative : true,
33572 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33576 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33578 minValue : Number.NEGATIVE_INFINITY,
33580 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33582 maxValue : Number.MAX_VALUE,
33584 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33586 minText : "The minimum value for this field is {0}",
33588 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33590 maxText : "The maximum value for this field is {0}",
33592 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33593 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33595 nanText : "{0} is not a valid number",
33597 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33599 thousandsDelimiter : false,
33601 * @cfg {String} valueAlign alignment of value
33603 valueAlign : "left",
33605 getAutoCreate : function()
33607 var hiddenInput = {
33611 cls: 'hidden-number-input'
33615 hiddenInput.name = this.name;
33620 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33622 this.name = hiddenInput.name;
33624 if(cfg.cn.length > 0) {
33625 cfg.cn.push(hiddenInput);
33632 initEvents : function()
33634 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33636 var allowed = "0123456789";
33638 if(this.allowDecimals){
33639 allowed += this.decimalSeparator;
33642 if(this.allowNegative){
33646 if(this.thousandsDelimiter) {
33650 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33652 var keyPress = function(e){
33654 var k = e.getKey();
33656 var c = e.getCharCode();
33659 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33660 allowed.indexOf(String.fromCharCode(c)) === -1
33666 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33670 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33675 this.el.on("keypress", keyPress, this);
33678 validateValue : function(value)
33681 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33685 var num = this.parseValue(value);
33688 this.markInvalid(String.format(this.nanText, value));
33692 if(num < this.minValue){
33693 this.markInvalid(String.format(this.minText, this.minValue));
33697 if(num > this.maxValue){
33698 this.markInvalid(String.format(this.maxText, this.maxValue));
33705 getValue : function()
33707 var v = this.hiddenEl().getValue();
33709 return this.fixPrecision(this.parseValue(v));
33712 parseValue : function(value)
33714 if(this.thousandsDelimiter) {
33716 r = new RegExp(",", "g");
33717 value = value.replace(r, "");
33720 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33721 return isNaN(value) ? '' : value;
33724 fixPrecision : function(value)
33726 if(this.thousandsDelimiter) {
33728 r = new RegExp(",", "g");
33729 value = value.replace(r, "");
33732 var nan = isNaN(value);
33734 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33735 return nan ? '' : value;
33737 return parseFloat(value).toFixed(this.decimalPrecision);
33740 setValue : function(v)
33742 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33748 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33750 this.inputEl().dom.value = (v == '') ? '' :
33751 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33753 if(!this.allowZero && v === '0') {
33754 this.hiddenEl().dom.value = '';
33755 this.inputEl().dom.value = '';
33762 decimalPrecisionFcn : function(v)
33764 return Math.floor(v);
33767 beforeBlur : function()
33769 var v = this.parseValue(this.getRawValue());
33771 if(v || v === 0 || v === ''){
33776 hiddenEl : function()
33778 return this.el.select('input.hidden-number-input',true).first();
33790 * @class Roo.bootstrap.DocumentSlider
33791 * @extends Roo.bootstrap.Component
33792 * Bootstrap DocumentSlider class
33795 * Create a new DocumentViewer
33796 * @param {Object} config The config object
33799 Roo.bootstrap.DocumentSlider = function(config){
33800 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33807 * Fire after initEvent
33808 * @param {Roo.bootstrap.DocumentSlider} this
33813 * Fire after update
33814 * @param {Roo.bootstrap.DocumentSlider} this
33820 * @param {Roo.bootstrap.DocumentSlider} this
33826 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33832 getAutoCreate : function()
33836 cls : 'roo-document-slider',
33840 cls : 'roo-document-slider-header',
33844 cls : 'roo-document-slider-header-title'
33850 cls : 'roo-document-slider-body',
33854 cls : 'roo-document-slider-prev',
33858 cls : 'fa fa-chevron-left'
33864 cls : 'roo-document-slider-thumb',
33868 cls : 'roo-document-slider-image'
33874 cls : 'roo-document-slider-next',
33878 cls : 'fa fa-chevron-right'
33890 initEvents : function()
33892 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33893 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33895 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33896 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33898 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33899 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33901 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33902 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33904 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33905 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33907 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33908 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33910 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33911 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33913 this.thumbEl.on('click', this.onClick, this);
33915 this.prevIndicator.on('click', this.prev, this);
33917 this.nextIndicator.on('click', this.next, this);
33921 initial : function()
33923 if(this.files.length){
33924 this.indicator = 1;
33928 this.fireEvent('initial', this);
33931 update : function()
33933 this.imageEl.attr('src', this.files[this.indicator - 1]);
33935 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33937 this.prevIndicator.show();
33939 if(this.indicator == 1){
33940 this.prevIndicator.hide();
33943 this.nextIndicator.show();
33945 if(this.indicator == this.files.length){
33946 this.nextIndicator.hide();
33949 this.thumbEl.scrollTo('top');
33951 this.fireEvent('update', this);
33954 onClick : function(e)
33956 e.preventDefault();
33958 this.fireEvent('click', this);
33963 e.preventDefault();
33965 this.indicator = Math.max(1, this.indicator - 1);
33972 e.preventDefault();
33974 this.indicator = Math.min(this.files.length, this.indicator + 1);
33988 * @class Roo.bootstrap.RadioSet
33989 * @extends Roo.bootstrap.Input
33990 * Bootstrap RadioSet class
33991 * @cfg {String} indicatorpos (left|right) default left
33992 * @cfg {Boolean} inline (true|false) inline the element (default true)
33993 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33995 * Create a new RadioSet
33996 * @param {Object} config The config object
33999 Roo.bootstrap.RadioSet = function(config){
34001 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34005 Roo.bootstrap.RadioSet.register(this);
34010 * Fires when the element is checked or unchecked.
34011 * @param {Roo.bootstrap.RadioSet} this This radio
34012 * @param {Roo.bootstrap.Radio} item The checked item
34017 * Fires when the element is click.
34018 * @param {Roo.bootstrap.RadioSet} this This radio set
34019 * @param {Roo.bootstrap.Radio} item The checked item
34020 * @param {Roo.EventObject} e The event object
34027 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34035 indicatorpos : 'left',
34037 getAutoCreate : function()
34041 cls : 'roo-radio-set-label',
34045 html : this.fieldLabel
34050 if(this.indicatorpos == 'left'){
34053 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34054 tooltip : 'This field is required'
34059 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34060 tooltip : 'This field is required'
34066 cls : 'roo-radio-set-items'
34069 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34071 if (align === 'left' && this.fieldLabel.length) {
34074 cls : "roo-radio-set-right",
34080 if(this.labelWidth > 12){
34081 label.style = "width: " + this.labelWidth + 'px';
34084 if(this.labelWidth < 13 && this.labelmd == 0){
34085 this.labelmd = this.labelWidth;
34088 if(this.labellg > 0){
34089 label.cls += ' col-lg-' + this.labellg;
34090 items.cls += ' col-lg-' + (12 - this.labellg);
34093 if(this.labelmd > 0){
34094 label.cls += ' col-md-' + this.labelmd;
34095 items.cls += ' col-md-' + (12 - this.labelmd);
34098 if(this.labelsm > 0){
34099 label.cls += ' col-sm-' + this.labelsm;
34100 items.cls += ' col-sm-' + (12 - this.labelsm);
34103 if(this.labelxs > 0){
34104 label.cls += ' col-xs-' + this.labelxs;
34105 items.cls += ' col-xs-' + (12 - this.labelxs);
34111 cls : 'roo-radio-set',
34115 cls : 'roo-radio-set-input',
34118 value : this.value ? this.value : ''
34125 if(this.weight.length){
34126 cfg.cls += ' roo-radio-' + this.weight;
34130 cfg.cls += ' roo-radio-set-inline';
34134 ['xs','sm','md','lg'].map(function(size){
34135 if (settings[size]) {
34136 cfg.cls += ' col-' + size + '-' + settings[size];
34144 initEvents : function()
34146 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34147 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34149 if(!this.fieldLabel.length){
34150 this.labelEl.hide();
34153 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34154 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34156 this.indicator = this.indicatorEl();
34158 if(this.indicator){
34159 this.indicator.addClass('invisible');
34162 this.originalValue = this.getValue();
34166 inputEl: function ()
34168 return this.el.select('.roo-radio-set-input', true).first();
34171 getChildContainer : function()
34173 return this.itemsEl;
34176 register : function(item)
34178 this.radioes.push(item);
34182 validate : function()
34184 if(this.getVisibilityEl().hasClass('hidden')){
34190 Roo.each(this.radioes, function(i){
34199 if(this.allowBlank) {
34203 if(this.disabled || valid){
34208 this.markInvalid();
34213 markValid : function()
34215 if(this.labelEl.isVisible(true)){
34216 this.indicatorEl().removeClass('visible');
34217 this.indicatorEl().addClass('invisible');
34220 this.el.removeClass([this.invalidClass, this.validClass]);
34221 this.el.addClass(this.validClass);
34223 this.fireEvent('valid', this);
34226 markInvalid : function(msg)
34228 if(this.allowBlank || this.disabled){
34232 if(this.labelEl.isVisible(true)){
34233 this.indicatorEl().removeClass('invisible');
34234 this.indicatorEl().addClass('visible');
34237 this.el.removeClass([this.invalidClass, this.validClass]);
34238 this.el.addClass(this.invalidClass);
34240 this.fireEvent('invalid', this, msg);
34244 setValue : function(v, suppressEvent)
34246 if(this.value === v){
34253 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34256 Roo.each(this.radioes, function(i){
34258 i.el.removeClass('checked');
34261 Roo.each(this.radioes, function(i){
34263 if(i.value === v || i.value.toString() === v.toString()){
34265 i.el.addClass('checked');
34267 if(suppressEvent !== true){
34268 this.fireEvent('check', this, i);
34279 clearInvalid : function(){
34281 if(!this.el || this.preventMark){
34285 this.el.removeClass([this.invalidClass]);
34287 this.fireEvent('valid', this);
34292 Roo.apply(Roo.bootstrap.RadioSet, {
34296 register : function(set)
34298 this.groups[set.name] = set;
34301 get: function(name)
34303 if (typeof(this.groups[name]) == 'undefined') {
34307 return this.groups[name] ;
34313 * Ext JS Library 1.1.1
34314 * Copyright(c) 2006-2007, Ext JS, LLC.
34316 * Originally Released Under LGPL - original licence link has changed is not relivant.
34319 * <script type="text/javascript">
34324 * @class Roo.bootstrap.SplitBar
34325 * @extends Roo.util.Observable
34326 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34330 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34331 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34332 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34333 split.minSize = 100;
34334 split.maxSize = 600;
34335 split.animate = true;
34336 split.on('moved', splitterMoved);
34339 * Create a new SplitBar
34340 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34341 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34342 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34343 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34344 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34345 position of the SplitBar).
34347 Roo.bootstrap.SplitBar = function(cfg){
34352 // dragElement : elm
34353 // resizingElement: el,
34355 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34356 // placement : Roo.bootstrap.SplitBar.LEFT ,
34357 // existingProxy ???
34360 this.el = Roo.get(cfg.dragElement, true);
34361 this.el.dom.unselectable = "on";
34363 this.resizingEl = Roo.get(cfg.resizingElement, true);
34367 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34368 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34371 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34374 * The minimum size of the resizing element. (Defaults to 0)
34380 * The maximum size of the resizing element. (Defaults to 2000)
34383 this.maxSize = 2000;
34386 * Whether to animate the transition to the new size
34389 this.animate = false;
34392 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34395 this.useShim = false;
34400 if(!cfg.existingProxy){
34402 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34404 this.proxy = Roo.get(cfg.existingProxy).dom;
34407 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34410 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34413 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34416 this.dragSpecs = {};
34419 * @private The adapter to use to positon and resize elements
34421 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34422 this.adapter.init(this);
34424 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34426 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34427 this.el.addClass("roo-splitbar-h");
34430 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34431 this.el.addClass("roo-splitbar-v");
34437 * Fires when the splitter is moved (alias for {@link #event-moved})
34438 * @param {Roo.bootstrap.SplitBar} this
34439 * @param {Number} newSize the new width or height
34444 * Fires when the splitter is moved
34445 * @param {Roo.bootstrap.SplitBar} this
34446 * @param {Number} newSize the new width or height
34450 * @event beforeresize
34451 * Fires before the splitter is dragged
34452 * @param {Roo.bootstrap.SplitBar} this
34454 "beforeresize" : true,
34456 "beforeapply" : true
34459 Roo.util.Observable.call(this);
34462 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34463 onStartProxyDrag : function(x, y){
34464 this.fireEvent("beforeresize", this);
34466 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34468 o.enableDisplayMode("block");
34469 // all splitbars share the same overlay
34470 Roo.bootstrap.SplitBar.prototype.overlay = o;
34472 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34473 this.overlay.show();
34474 Roo.get(this.proxy).setDisplayed("block");
34475 var size = this.adapter.getElementSize(this);
34476 this.activeMinSize = this.getMinimumSize();;
34477 this.activeMaxSize = this.getMaximumSize();;
34478 var c1 = size - this.activeMinSize;
34479 var c2 = Math.max(this.activeMaxSize - size, 0);
34480 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34481 this.dd.resetConstraints();
34482 this.dd.setXConstraint(
34483 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34484 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34486 this.dd.setYConstraint(0, 0);
34488 this.dd.resetConstraints();
34489 this.dd.setXConstraint(0, 0);
34490 this.dd.setYConstraint(
34491 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34492 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34495 this.dragSpecs.startSize = size;
34496 this.dragSpecs.startPoint = [x, y];
34497 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34501 * @private Called after the drag operation by the DDProxy
34503 onEndProxyDrag : function(e){
34504 Roo.get(this.proxy).setDisplayed(false);
34505 var endPoint = Roo.lib.Event.getXY(e);
34507 this.overlay.hide();
34510 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34511 newSize = this.dragSpecs.startSize +
34512 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34513 endPoint[0] - this.dragSpecs.startPoint[0] :
34514 this.dragSpecs.startPoint[0] - endPoint[0]
34517 newSize = this.dragSpecs.startSize +
34518 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34519 endPoint[1] - this.dragSpecs.startPoint[1] :
34520 this.dragSpecs.startPoint[1] - endPoint[1]
34523 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34524 if(newSize != this.dragSpecs.startSize){
34525 if(this.fireEvent('beforeapply', this, newSize) !== false){
34526 this.adapter.setElementSize(this, newSize);
34527 this.fireEvent("moved", this, newSize);
34528 this.fireEvent("resize", this, newSize);
34534 * Get the adapter this SplitBar uses
34535 * @return The adapter object
34537 getAdapter : function(){
34538 return this.adapter;
34542 * Set the adapter this SplitBar uses
34543 * @param {Object} adapter A SplitBar adapter object
34545 setAdapter : function(adapter){
34546 this.adapter = adapter;
34547 this.adapter.init(this);
34551 * Gets the minimum size for the resizing element
34552 * @return {Number} The minimum size
34554 getMinimumSize : function(){
34555 return this.minSize;
34559 * Sets the minimum size for the resizing element
34560 * @param {Number} minSize The minimum size
34562 setMinimumSize : function(minSize){
34563 this.minSize = minSize;
34567 * Gets the maximum size for the resizing element
34568 * @return {Number} The maximum size
34570 getMaximumSize : function(){
34571 return this.maxSize;
34575 * Sets the maximum size for the resizing element
34576 * @param {Number} maxSize The maximum size
34578 setMaximumSize : function(maxSize){
34579 this.maxSize = maxSize;
34583 * Sets the initialize size for the resizing element
34584 * @param {Number} size The initial size
34586 setCurrentSize : function(size){
34587 var oldAnimate = this.animate;
34588 this.animate = false;
34589 this.adapter.setElementSize(this, size);
34590 this.animate = oldAnimate;
34594 * Destroy this splitbar.
34595 * @param {Boolean} removeEl True to remove the element
34597 destroy : function(removeEl){
34599 this.shim.remove();
34602 this.proxy.parentNode.removeChild(this.proxy);
34610 * @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.
34612 Roo.bootstrap.SplitBar.createProxy = function(dir){
34613 var proxy = new Roo.Element(document.createElement("div"));
34614 proxy.unselectable();
34615 var cls = 'roo-splitbar-proxy';
34616 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34617 document.body.appendChild(proxy.dom);
34622 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34623 * Default Adapter. It assumes the splitter and resizing element are not positioned
34624 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34626 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34629 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34630 // do nothing for now
34631 init : function(s){
34635 * Called before drag operations to get the current size of the resizing element.
34636 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34638 getElementSize : function(s){
34639 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34640 return s.resizingEl.getWidth();
34642 return s.resizingEl.getHeight();
34647 * Called after drag operations to set the size of the resizing element.
34648 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34649 * @param {Number} newSize The new size to set
34650 * @param {Function} onComplete A function to be invoked when resizing is complete
34652 setElementSize : function(s, newSize, onComplete){
34653 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34655 s.resizingEl.setWidth(newSize);
34657 onComplete(s, newSize);
34660 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34665 s.resizingEl.setHeight(newSize);
34667 onComplete(s, newSize);
34670 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34677 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34678 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34679 * Adapter that moves the splitter element to align with the resized sizing element.
34680 * Used with an absolute positioned SplitBar.
34681 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34682 * document.body, make sure you assign an id to the body element.
34684 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34685 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34686 this.container = Roo.get(container);
34689 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34690 init : function(s){
34691 this.basic.init(s);
34694 getElementSize : function(s){
34695 return this.basic.getElementSize(s);
34698 setElementSize : function(s, newSize, onComplete){
34699 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34702 moveSplitter : function(s){
34703 var yes = Roo.bootstrap.SplitBar;
34704 switch(s.placement){
34706 s.el.setX(s.resizingEl.getRight());
34709 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34712 s.el.setY(s.resizingEl.getBottom());
34715 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34722 * Orientation constant - Create a vertical SplitBar
34726 Roo.bootstrap.SplitBar.VERTICAL = 1;
34729 * Orientation constant - Create a horizontal SplitBar
34733 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34736 * Placement constant - The resizing element is to the left of the splitter element
34740 Roo.bootstrap.SplitBar.LEFT = 1;
34743 * Placement constant - The resizing element is to the right of the splitter element
34747 Roo.bootstrap.SplitBar.RIGHT = 2;
34750 * Placement constant - The resizing element is positioned above the splitter element
34754 Roo.bootstrap.SplitBar.TOP = 3;
34757 * Placement constant - The resizing element is positioned under splitter element
34761 Roo.bootstrap.SplitBar.BOTTOM = 4;
34762 Roo.namespace("Roo.bootstrap.layout");/*
34764 * Ext JS Library 1.1.1
34765 * Copyright(c) 2006-2007, Ext JS, LLC.
34767 * Originally Released Under LGPL - original licence link has changed is not relivant.
34770 * <script type="text/javascript">
34774 * @class Roo.bootstrap.layout.Manager
34775 * @extends Roo.bootstrap.Component
34776 * Base class for layout managers.
34778 Roo.bootstrap.layout.Manager = function(config)
34780 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34786 /** false to disable window resize monitoring @type Boolean */
34787 this.monitorWindowResize = true;
34792 * Fires when a layout is performed.
34793 * @param {Roo.LayoutManager} this
34797 * @event regionresized
34798 * Fires when the user resizes a region.
34799 * @param {Roo.LayoutRegion} region The resized region
34800 * @param {Number} newSize The new size (width for east/west, height for north/south)
34802 "regionresized" : true,
34804 * @event regioncollapsed
34805 * Fires when a region is collapsed.
34806 * @param {Roo.LayoutRegion} region The collapsed region
34808 "regioncollapsed" : true,
34810 * @event regionexpanded
34811 * Fires when a region is expanded.
34812 * @param {Roo.LayoutRegion} region The expanded region
34814 "regionexpanded" : true
34816 this.updating = false;
34819 this.el = Roo.get(config.el);
34825 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34830 monitorWindowResize : true,
34836 onRender : function(ct, position)
34839 this.el = Roo.get(ct);
34842 //this.fireEvent('render',this);
34846 initEvents: function()
34850 // ie scrollbar fix
34851 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34852 document.body.scroll = "no";
34853 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34854 this.el.position('relative');
34856 this.id = this.el.id;
34857 this.el.addClass("roo-layout-container");
34858 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34859 if(this.el.dom != document.body ) {
34860 this.el.on('resize', this.layout,this);
34861 this.el.on('show', this.layout,this);
34867 * Returns true if this layout is currently being updated
34868 * @return {Boolean}
34870 isUpdating : function(){
34871 return this.updating;
34875 * Suspend the LayoutManager from doing auto-layouts while
34876 * making multiple add or remove calls
34878 beginUpdate : function(){
34879 this.updating = true;
34883 * Restore auto-layouts and optionally disable the manager from performing a layout
34884 * @param {Boolean} noLayout true to disable a layout update
34886 endUpdate : function(noLayout){
34887 this.updating = false;
34893 layout: function(){
34897 onRegionResized : function(region, newSize){
34898 this.fireEvent("regionresized", region, newSize);
34902 onRegionCollapsed : function(region){
34903 this.fireEvent("regioncollapsed", region);
34906 onRegionExpanded : function(region){
34907 this.fireEvent("regionexpanded", region);
34911 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34912 * performs box-model adjustments.
34913 * @return {Object} The size as an object {width: (the width), height: (the height)}
34915 getViewSize : function()
34918 if(this.el.dom != document.body){
34919 size = this.el.getSize();
34921 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34923 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34924 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34929 * Returns the Element this layout is bound to.
34930 * @return {Roo.Element}
34932 getEl : function(){
34937 * Returns the specified region.
34938 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34939 * @return {Roo.LayoutRegion}
34941 getRegion : function(target){
34942 return this.regions[target.toLowerCase()];
34945 onWindowResize : function(){
34946 if(this.monitorWindowResize){
34953 * Ext JS Library 1.1.1
34954 * Copyright(c) 2006-2007, Ext JS, LLC.
34956 * Originally Released Under LGPL - original licence link has changed is not relivant.
34959 * <script type="text/javascript">
34962 * @class Roo.bootstrap.layout.Border
34963 * @extends Roo.bootstrap.layout.Manager
34964 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34965 * please see: examples/bootstrap/nested.html<br><br>
34967 <b>The container the layout is rendered into can be either the body element or any other element.
34968 If it is not the body element, the container needs to either be an absolute positioned element,
34969 or you will need to add "position:relative" to the css of the container. You will also need to specify
34970 the container size if it is not the body element.</b>
34973 * Create a new Border
34974 * @param {Object} config Configuration options
34976 Roo.bootstrap.layout.Border = function(config){
34977 config = config || {};
34978 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34982 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34983 if(config[region]){
34984 config[region].region = region;
34985 this.addRegion(config[region]);
34991 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34993 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34995 * Creates and adds a new region if it doesn't already exist.
34996 * @param {String} target The target region key (north, south, east, west or center).
34997 * @param {Object} config The regions config object
34998 * @return {BorderLayoutRegion} The new region
35000 addRegion : function(config)
35002 if(!this.regions[config.region]){
35003 var r = this.factory(config);
35004 this.bindRegion(r);
35006 return this.regions[config.region];
35010 bindRegion : function(r){
35011 this.regions[r.config.region] = r;
35013 r.on("visibilitychange", this.layout, this);
35014 r.on("paneladded", this.layout, this);
35015 r.on("panelremoved", this.layout, this);
35016 r.on("invalidated", this.layout, this);
35017 r.on("resized", this.onRegionResized, this);
35018 r.on("collapsed", this.onRegionCollapsed, this);
35019 r.on("expanded", this.onRegionExpanded, this);
35023 * Performs a layout update.
35025 layout : function()
35027 if(this.updating) {
35031 // render all the rebions if they have not been done alreayd?
35032 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35033 if(this.regions[region] && !this.regions[region].bodyEl){
35034 this.regions[region].onRender(this.el)
35038 var size = this.getViewSize();
35039 var w = size.width;
35040 var h = size.height;
35045 //var x = 0, y = 0;
35047 var rs = this.regions;
35048 var north = rs["north"];
35049 var south = rs["south"];
35050 var west = rs["west"];
35051 var east = rs["east"];
35052 var center = rs["center"];
35053 //if(this.hideOnLayout){ // not supported anymore
35054 //c.el.setStyle("display", "none");
35056 if(north && north.isVisible()){
35057 var b = north.getBox();
35058 var m = north.getMargins();
35059 b.width = w - (m.left+m.right);
35062 centerY = b.height + b.y + m.bottom;
35063 centerH -= centerY;
35064 north.updateBox(this.safeBox(b));
35066 if(south && south.isVisible()){
35067 var b = south.getBox();
35068 var m = south.getMargins();
35069 b.width = w - (m.left+m.right);
35071 var totalHeight = (b.height + m.top + m.bottom);
35072 b.y = h - totalHeight + m.top;
35073 centerH -= totalHeight;
35074 south.updateBox(this.safeBox(b));
35076 if(west && west.isVisible()){
35077 var b = west.getBox();
35078 var m = west.getMargins();
35079 b.height = centerH - (m.top+m.bottom);
35081 b.y = centerY + m.top;
35082 var totalWidth = (b.width + m.left + m.right);
35083 centerX += totalWidth;
35084 centerW -= totalWidth;
35085 west.updateBox(this.safeBox(b));
35087 if(east && east.isVisible()){
35088 var b = east.getBox();
35089 var m = east.getMargins();
35090 b.height = centerH - (m.top+m.bottom);
35091 var totalWidth = (b.width + m.left + m.right);
35092 b.x = w - totalWidth + m.left;
35093 b.y = centerY + m.top;
35094 centerW -= totalWidth;
35095 east.updateBox(this.safeBox(b));
35098 var m = center.getMargins();
35100 x: centerX + m.left,
35101 y: centerY + m.top,
35102 width: centerW - (m.left+m.right),
35103 height: centerH - (m.top+m.bottom)
35105 //if(this.hideOnLayout){
35106 //center.el.setStyle("display", "block");
35108 center.updateBox(this.safeBox(centerBox));
35111 this.fireEvent("layout", this);
35115 safeBox : function(box){
35116 box.width = Math.max(0, box.width);
35117 box.height = Math.max(0, box.height);
35122 * Adds a ContentPanel (or subclass) to this layout.
35123 * @param {String} target The target region key (north, south, east, west or center).
35124 * @param {Roo.ContentPanel} panel The panel to add
35125 * @return {Roo.ContentPanel} The added panel
35127 add : function(target, panel){
35129 target = target.toLowerCase();
35130 return this.regions[target].add(panel);
35134 * Remove a ContentPanel (or subclass) to this layout.
35135 * @param {String} target The target region key (north, south, east, west or center).
35136 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35137 * @return {Roo.ContentPanel} The removed panel
35139 remove : function(target, panel){
35140 target = target.toLowerCase();
35141 return this.regions[target].remove(panel);
35145 * Searches all regions for a panel with the specified id
35146 * @param {String} panelId
35147 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35149 findPanel : function(panelId){
35150 var rs = this.regions;
35151 for(var target in rs){
35152 if(typeof rs[target] != "function"){
35153 var p = rs[target].getPanel(panelId);
35163 * Searches all regions for a panel with the specified id and activates (shows) it.
35164 * @param {String/ContentPanel} panelId The panels id or the panel itself
35165 * @return {Roo.ContentPanel} The shown panel or null
35167 showPanel : function(panelId) {
35168 var rs = this.regions;
35169 for(var target in rs){
35170 var r = rs[target];
35171 if(typeof r != "function"){
35172 if(r.hasPanel(panelId)){
35173 return r.showPanel(panelId);
35181 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35182 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35185 restoreState : function(provider){
35187 provider = Roo.state.Manager;
35189 var sm = new Roo.LayoutStateManager();
35190 sm.init(this, provider);
35196 * Adds a xtype elements to the layout.
35200 xtype : 'ContentPanel',
35207 xtype : 'NestedLayoutPanel',
35213 items : [ ... list of content panels or nested layout panels.. ]
35217 * @param {Object} cfg Xtype definition of item to add.
35219 addxtype : function(cfg)
35221 // basically accepts a pannel...
35222 // can accept a layout region..!?!?
35223 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35226 // theory? children can only be panels??
35228 //if (!cfg.xtype.match(/Panel$/)) {
35233 if (typeof(cfg.region) == 'undefined') {
35234 Roo.log("Failed to add Panel, region was not set");
35238 var region = cfg.region;
35244 xitems = cfg.items;
35251 case 'Content': // ContentPanel (el, cfg)
35252 case 'Scroll': // ContentPanel (el, cfg)
35254 cfg.autoCreate = true;
35255 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35257 // var el = this.el.createChild();
35258 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35261 this.add(region, ret);
35265 case 'TreePanel': // our new panel!
35266 cfg.el = this.el.createChild();
35267 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35268 this.add(region, ret);
35273 // create a new Layout (which is a Border Layout...
35275 var clayout = cfg.layout;
35276 clayout.el = this.el.createChild();
35277 clayout.items = clayout.items || [];
35281 // replace this exitems with the clayout ones..
35282 xitems = clayout.items;
35284 // force background off if it's in center...
35285 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35286 cfg.background = false;
35288 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35291 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35292 //console.log('adding nested layout panel ' + cfg.toSource());
35293 this.add(region, ret);
35294 nb = {}; /// find first...
35299 // needs grid and region
35301 //var el = this.getRegion(region).el.createChild();
35303 *var el = this.el.createChild();
35304 // create the grid first...
35305 cfg.grid.container = el;
35306 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35309 if (region == 'center' && this.active ) {
35310 cfg.background = false;
35313 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35315 this.add(region, ret);
35317 if (cfg.background) {
35318 // render grid on panel activation (if panel background)
35319 ret.on('activate', function(gp) {
35320 if (!gp.grid.rendered) {
35321 // gp.grid.render(el);
35325 // cfg.grid.render(el);
35331 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35332 // it was the old xcomponent building that caused this before.
35333 // espeically if border is the top element in the tree.
35343 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35345 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35346 this.add(region, ret);
35350 throw "Can not add '" + cfg.xtype + "' to Border";
35356 this.beginUpdate();
35360 Roo.each(xitems, function(i) {
35361 region = nb && i.region ? i.region : false;
35363 var add = ret.addxtype(i);
35366 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35367 if (!i.background) {
35368 abn[region] = nb[region] ;
35375 // make the last non-background panel active..
35376 //if (nb) { Roo.log(abn); }
35379 for(var r in abn) {
35380 region = this.getRegion(r);
35382 // tried using nb[r], but it does not work..
35384 region.showPanel(abn[r]);
35395 factory : function(cfg)
35398 var validRegions = Roo.bootstrap.layout.Border.regions;
35400 var target = cfg.region;
35403 var r = Roo.bootstrap.layout;
35407 return new r.North(cfg);
35409 return new r.South(cfg);
35411 return new r.East(cfg);
35413 return new r.West(cfg);
35415 return new r.Center(cfg);
35417 throw 'Layout region "'+target+'" not supported.';
35424 * Ext JS Library 1.1.1
35425 * Copyright(c) 2006-2007, Ext JS, LLC.
35427 * Originally Released Under LGPL - original licence link has changed is not relivant.
35430 * <script type="text/javascript">
35434 * @class Roo.bootstrap.layout.Basic
35435 * @extends Roo.util.Observable
35436 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35437 * and does not have a titlebar, tabs or any other features. All it does is size and position
35438 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35439 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35440 * @cfg {string} region the region that it inhabits..
35441 * @cfg {bool} skipConfig skip config?
35445 Roo.bootstrap.layout.Basic = function(config){
35447 this.mgr = config.mgr;
35449 this.position = config.region;
35451 var skipConfig = config.skipConfig;
35455 * @scope Roo.BasicLayoutRegion
35459 * @event beforeremove
35460 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35461 * @param {Roo.LayoutRegion} this
35462 * @param {Roo.ContentPanel} panel The panel
35463 * @param {Object} e The cancel event object
35465 "beforeremove" : true,
35467 * @event invalidated
35468 * Fires when the layout for this region is changed.
35469 * @param {Roo.LayoutRegion} this
35471 "invalidated" : true,
35473 * @event visibilitychange
35474 * Fires when this region is shown or hidden
35475 * @param {Roo.LayoutRegion} this
35476 * @param {Boolean} visibility true or false
35478 "visibilitychange" : true,
35480 * @event paneladded
35481 * Fires when a panel is added.
35482 * @param {Roo.LayoutRegion} this
35483 * @param {Roo.ContentPanel} panel The panel
35485 "paneladded" : true,
35487 * @event panelremoved
35488 * Fires when a panel is removed.
35489 * @param {Roo.LayoutRegion} this
35490 * @param {Roo.ContentPanel} panel The panel
35492 "panelremoved" : true,
35494 * @event beforecollapse
35495 * Fires when this region before collapse.
35496 * @param {Roo.LayoutRegion} this
35498 "beforecollapse" : true,
35501 * Fires when this region is collapsed.
35502 * @param {Roo.LayoutRegion} this
35504 "collapsed" : true,
35507 * Fires when this region is expanded.
35508 * @param {Roo.LayoutRegion} this
35513 * Fires when this region is slid into view.
35514 * @param {Roo.LayoutRegion} this
35516 "slideshow" : true,
35519 * Fires when this region slides out of view.
35520 * @param {Roo.LayoutRegion} this
35522 "slidehide" : true,
35524 * @event panelactivated
35525 * Fires when a panel is activated.
35526 * @param {Roo.LayoutRegion} this
35527 * @param {Roo.ContentPanel} panel The activated panel
35529 "panelactivated" : true,
35532 * Fires when the user resizes this region.
35533 * @param {Roo.LayoutRegion} this
35534 * @param {Number} newSize The new size (width for east/west, height for north/south)
35538 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35539 this.panels = new Roo.util.MixedCollection();
35540 this.panels.getKey = this.getPanelId.createDelegate(this);
35542 this.activePanel = null;
35543 // ensure listeners are added...
35545 if (config.listeners || config.events) {
35546 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35547 listeners : config.listeners || {},
35548 events : config.events || {}
35552 if(skipConfig !== true){
35553 this.applyConfig(config);
35557 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35559 getPanelId : function(p){
35563 applyConfig : function(config){
35564 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35565 this.config = config;
35570 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35571 * the width, for horizontal (north, south) the height.
35572 * @param {Number} newSize The new width or height
35574 resizeTo : function(newSize){
35575 var el = this.el ? this.el :
35576 (this.activePanel ? this.activePanel.getEl() : null);
35578 switch(this.position){
35581 el.setWidth(newSize);
35582 this.fireEvent("resized", this, newSize);
35586 el.setHeight(newSize);
35587 this.fireEvent("resized", this, newSize);
35593 getBox : function(){
35594 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35597 getMargins : function(){
35598 return this.margins;
35601 updateBox : function(box){
35603 var el = this.activePanel.getEl();
35604 el.dom.style.left = box.x + "px";
35605 el.dom.style.top = box.y + "px";
35606 this.activePanel.setSize(box.width, box.height);
35610 * Returns the container element for this region.
35611 * @return {Roo.Element}
35613 getEl : function(){
35614 return this.activePanel;
35618 * Returns true if this region is currently visible.
35619 * @return {Boolean}
35621 isVisible : function(){
35622 return this.activePanel ? true : false;
35625 setActivePanel : function(panel){
35626 panel = this.getPanel(panel);
35627 if(this.activePanel && this.activePanel != panel){
35628 this.activePanel.setActiveState(false);
35629 this.activePanel.getEl().setLeftTop(-10000,-10000);
35631 this.activePanel = panel;
35632 panel.setActiveState(true);
35634 panel.setSize(this.box.width, this.box.height);
35636 this.fireEvent("panelactivated", this, panel);
35637 this.fireEvent("invalidated");
35641 * Show the specified panel.
35642 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35643 * @return {Roo.ContentPanel} The shown panel or null
35645 showPanel : function(panel){
35646 panel = this.getPanel(panel);
35648 this.setActivePanel(panel);
35654 * Get the active panel for this region.
35655 * @return {Roo.ContentPanel} The active panel or null
35657 getActivePanel : function(){
35658 return this.activePanel;
35662 * Add the passed ContentPanel(s)
35663 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35664 * @return {Roo.ContentPanel} The panel added (if only one was added)
35666 add : function(panel){
35667 if(arguments.length > 1){
35668 for(var i = 0, len = arguments.length; i < len; i++) {
35669 this.add(arguments[i]);
35673 if(this.hasPanel(panel)){
35674 this.showPanel(panel);
35677 var el = panel.getEl();
35678 if(el.dom.parentNode != this.mgr.el.dom){
35679 this.mgr.el.dom.appendChild(el.dom);
35681 if(panel.setRegion){
35682 panel.setRegion(this);
35684 this.panels.add(panel);
35685 el.setStyle("position", "absolute");
35686 if(!panel.background){
35687 this.setActivePanel(panel);
35688 if(this.config.initialSize && this.panels.getCount()==1){
35689 this.resizeTo(this.config.initialSize);
35692 this.fireEvent("paneladded", this, panel);
35697 * Returns true if the panel is in this region.
35698 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35699 * @return {Boolean}
35701 hasPanel : function(panel){
35702 if(typeof panel == "object"){ // must be panel obj
35703 panel = panel.getId();
35705 return this.getPanel(panel) ? true : false;
35709 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35710 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35711 * @param {Boolean} preservePanel Overrides the config preservePanel option
35712 * @return {Roo.ContentPanel} The panel that was removed
35714 remove : function(panel, preservePanel){
35715 panel = this.getPanel(panel);
35720 this.fireEvent("beforeremove", this, panel, e);
35721 if(e.cancel === true){
35724 var panelId = panel.getId();
35725 this.panels.removeKey(panelId);
35730 * Returns the panel specified or null if it's not in this region.
35731 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35732 * @return {Roo.ContentPanel}
35734 getPanel : function(id){
35735 if(typeof id == "object"){ // must be panel obj
35738 return this.panels.get(id);
35742 * Returns this regions position (north/south/east/west/center).
35745 getPosition: function(){
35746 return this.position;
35750 * Ext JS Library 1.1.1
35751 * Copyright(c) 2006-2007, Ext JS, LLC.
35753 * Originally Released Under LGPL - original licence link has changed is not relivant.
35756 * <script type="text/javascript">
35760 * @class Roo.bootstrap.layout.Region
35761 * @extends Roo.bootstrap.layout.Basic
35762 * This class represents a region in a layout manager.
35764 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35765 * @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})
35766 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35767 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35768 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35769 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35770 * @cfg {String} title The title for the region (overrides panel titles)
35771 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35772 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35773 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35774 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35775 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35776 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35777 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35778 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35779 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35780 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35782 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35783 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35784 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35785 * @cfg {Number} width For East/West panels
35786 * @cfg {Number} height For North/South panels
35787 * @cfg {Boolean} split To show the splitter
35788 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35790 * @cfg {string} cls Extra CSS classes to add to region
35792 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35793 * @cfg {string} region the region that it inhabits..
35796 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35797 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35799 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35800 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35801 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35803 Roo.bootstrap.layout.Region = function(config)
35805 this.applyConfig(config);
35807 var mgr = config.mgr;
35808 var pos = config.region;
35809 config.skipConfig = true;
35810 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35813 this.onRender(mgr.el);
35816 this.visible = true;
35817 this.collapsed = false;
35818 this.unrendered_panels = [];
35821 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35823 position: '', // set by wrapper (eg. north/south etc..)
35824 unrendered_panels : null, // unrendered panels.
35825 createBody : function(){
35826 /** This region's body element
35827 * @type Roo.Element */
35828 this.bodyEl = this.el.createChild({
35830 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35834 onRender: function(ctr, pos)
35836 var dh = Roo.DomHelper;
35837 /** This region's container element
35838 * @type Roo.Element */
35839 this.el = dh.append(ctr.dom, {
35841 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35843 /** This region's title element
35844 * @type Roo.Element */
35846 this.titleEl = dh.append(this.el.dom,
35849 unselectable: "on",
35850 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35852 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35853 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35856 this.titleEl.enableDisplayMode();
35857 /** This region's title text element
35858 * @type HTMLElement */
35859 this.titleTextEl = this.titleEl.dom.firstChild;
35860 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35862 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35863 this.closeBtn.enableDisplayMode();
35864 this.closeBtn.on("click", this.closeClicked, this);
35865 this.closeBtn.hide();
35867 this.createBody(this.config);
35868 if(this.config.hideWhenEmpty){
35870 this.on("paneladded", this.validateVisibility, this);
35871 this.on("panelremoved", this.validateVisibility, this);
35873 if(this.autoScroll){
35874 this.bodyEl.setStyle("overflow", "auto");
35876 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35878 //if(c.titlebar !== false){
35879 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35880 this.titleEl.hide();
35882 this.titleEl.show();
35883 if(this.config.title){
35884 this.titleTextEl.innerHTML = this.config.title;
35888 if(this.config.collapsed){
35889 this.collapse(true);
35891 if(this.config.hidden){
35895 if (this.unrendered_panels && this.unrendered_panels.length) {
35896 for (var i =0;i< this.unrendered_panels.length; i++) {
35897 this.add(this.unrendered_panels[i]);
35899 this.unrendered_panels = null;
35905 applyConfig : function(c)
35908 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35909 var dh = Roo.DomHelper;
35910 if(c.titlebar !== false){
35911 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35912 this.collapseBtn.on("click", this.collapse, this);
35913 this.collapseBtn.enableDisplayMode();
35915 if(c.showPin === true || this.showPin){
35916 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35917 this.stickBtn.enableDisplayMode();
35918 this.stickBtn.on("click", this.expand, this);
35919 this.stickBtn.hide();
35924 /** This region's collapsed element
35925 * @type Roo.Element */
35928 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35929 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35932 if(c.floatable !== false){
35933 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35934 this.collapsedEl.on("click", this.collapseClick, this);
35937 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35938 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35939 id: "message", unselectable: "on", style:{"float":"left"}});
35940 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35942 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35943 this.expandBtn.on("click", this.expand, this);
35947 if(this.collapseBtn){
35948 this.collapseBtn.setVisible(c.collapsible == true);
35951 this.cmargins = c.cmargins || this.cmargins ||
35952 (this.position == "west" || this.position == "east" ?
35953 {top: 0, left: 2, right:2, bottom: 0} :
35954 {top: 2, left: 0, right:0, bottom: 2});
35956 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35959 this.bottomTabs = c.tabPosition != "top";
35961 this.autoScroll = c.autoScroll || false;
35966 this.duration = c.duration || .30;
35967 this.slideDuration = c.slideDuration || .45;
35972 * Returns true if this region is currently visible.
35973 * @return {Boolean}
35975 isVisible : function(){
35976 return this.visible;
35980 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35981 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35983 //setCollapsedTitle : function(title){
35984 // title = title || " ";
35985 // if(this.collapsedTitleTextEl){
35986 // this.collapsedTitleTextEl.innerHTML = title;
35990 getBox : function(){
35992 // if(!this.collapsed){
35993 b = this.el.getBox(false, true);
35995 // b = this.collapsedEl.getBox(false, true);
36000 getMargins : function(){
36001 return this.margins;
36002 //return this.collapsed ? this.cmargins : this.margins;
36005 highlight : function(){
36006 this.el.addClass("x-layout-panel-dragover");
36009 unhighlight : function(){
36010 this.el.removeClass("x-layout-panel-dragover");
36013 updateBox : function(box)
36015 if (!this.bodyEl) {
36016 return; // not rendered yet..
36020 if(!this.collapsed){
36021 this.el.dom.style.left = box.x + "px";
36022 this.el.dom.style.top = box.y + "px";
36023 this.updateBody(box.width, box.height);
36025 this.collapsedEl.dom.style.left = box.x + "px";
36026 this.collapsedEl.dom.style.top = box.y + "px";
36027 this.collapsedEl.setSize(box.width, box.height);
36030 this.tabs.autoSizeTabs();
36034 updateBody : function(w, h)
36037 this.el.setWidth(w);
36038 w -= this.el.getBorderWidth("rl");
36039 if(this.config.adjustments){
36040 w += this.config.adjustments[0];
36043 if(h !== null && h > 0){
36044 this.el.setHeight(h);
36045 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36046 h -= this.el.getBorderWidth("tb");
36047 if(this.config.adjustments){
36048 h += this.config.adjustments[1];
36050 this.bodyEl.setHeight(h);
36052 h = this.tabs.syncHeight(h);
36055 if(this.panelSize){
36056 w = w !== null ? w : this.panelSize.width;
36057 h = h !== null ? h : this.panelSize.height;
36059 if(this.activePanel){
36060 var el = this.activePanel.getEl();
36061 w = w !== null ? w : el.getWidth();
36062 h = h !== null ? h : el.getHeight();
36063 this.panelSize = {width: w, height: h};
36064 this.activePanel.setSize(w, h);
36066 if(Roo.isIE && this.tabs){
36067 this.tabs.el.repaint();
36072 * Returns the container element for this region.
36073 * @return {Roo.Element}
36075 getEl : function(){
36080 * Hides this region.
36083 //if(!this.collapsed){
36084 this.el.dom.style.left = "-2000px";
36087 // this.collapsedEl.dom.style.left = "-2000px";
36088 // this.collapsedEl.hide();
36090 this.visible = false;
36091 this.fireEvent("visibilitychange", this, false);
36095 * Shows this region if it was previously hidden.
36098 //if(!this.collapsed){
36101 // this.collapsedEl.show();
36103 this.visible = true;
36104 this.fireEvent("visibilitychange", this, true);
36107 closeClicked : function(){
36108 if(this.activePanel){
36109 this.remove(this.activePanel);
36113 collapseClick : function(e){
36115 e.stopPropagation();
36118 e.stopPropagation();
36124 * Collapses this region.
36125 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36128 collapse : function(skipAnim, skipCheck = false){
36129 if(this.collapsed) {
36133 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36135 this.collapsed = true;
36137 this.split.el.hide();
36139 if(this.config.animate && skipAnim !== true){
36140 this.fireEvent("invalidated", this);
36141 this.animateCollapse();
36143 this.el.setLocation(-20000,-20000);
36145 this.collapsedEl.show();
36146 this.fireEvent("collapsed", this);
36147 this.fireEvent("invalidated", this);
36153 animateCollapse : function(){
36158 * Expands this region if it was previously collapsed.
36159 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36160 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36163 expand : function(e, skipAnim){
36165 e.stopPropagation();
36167 if(!this.collapsed || this.el.hasActiveFx()) {
36171 this.afterSlideIn();
36174 this.collapsed = false;
36175 if(this.config.animate && skipAnim !== true){
36176 this.animateExpand();
36180 this.split.el.show();
36182 this.collapsedEl.setLocation(-2000,-2000);
36183 this.collapsedEl.hide();
36184 this.fireEvent("invalidated", this);
36185 this.fireEvent("expanded", this);
36189 animateExpand : function(){
36193 initTabs : function()
36195 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36197 var ts = new Roo.bootstrap.panel.Tabs({
36198 el: this.bodyEl.dom,
36199 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36200 disableTooltips: this.config.disableTabTips,
36201 toolbar : this.config.toolbar
36204 if(this.config.hideTabs){
36205 ts.stripWrap.setDisplayed(false);
36208 ts.resizeTabs = this.config.resizeTabs === true;
36209 ts.minTabWidth = this.config.minTabWidth || 40;
36210 ts.maxTabWidth = this.config.maxTabWidth || 250;
36211 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36212 ts.monitorResize = false;
36213 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36214 ts.bodyEl.addClass('roo-layout-tabs-body');
36215 this.panels.each(this.initPanelAsTab, this);
36218 initPanelAsTab : function(panel){
36219 var ti = this.tabs.addTab(
36223 this.config.closeOnTab && panel.isClosable(),
36226 if(panel.tabTip !== undefined){
36227 ti.setTooltip(panel.tabTip);
36229 ti.on("activate", function(){
36230 this.setActivePanel(panel);
36233 if(this.config.closeOnTab){
36234 ti.on("beforeclose", function(t, e){
36236 this.remove(panel);
36240 panel.tabItem = ti;
36245 updatePanelTitle : function(panel, title)
36247 if(this.activePanel == panel){
36248 this.updateTitle(title);
36251 var ti = this.tabs.getTab(panel.getEl().id);
36253 if(panel.tabTip !== undefined){
36254 ti.setTooltip(panel.tabTip);
36259 updateTitle : function(title){
36260 if(this.titleTextEl && !this.config.title){
36261 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36265 setActivePanel : function(panel)
36267 panel = this.getPanel(panel);
36268 if(this.activePanel && this.activePanel != panel){
36269 if(this.activePanel.setActiveState(false) === false){
36273 this.activePanel = panel;
36274 panel.setActiveState(true);
36275 if(this.panelSize){
36276 panel.setSize(this.panelSize.width, this.panelSize.height);
36279 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36281 this.updateTitle(panel.getTitle());
36283 this.fireEvent("invalidated", this);
36285 this.fireEvent("panelactivated", this, panel);
36289 * Shows the specified panel.
36290 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36291 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36293 showPanel : function(panel)
36295 panel = this.getPanel(panel);
36298 var tab = this.tabs.getTab(panel.getEl().id);
36299 if(tab.isHidden()){
36300 this.tabs.unhideTab(tab.id);
36304 this.setActivePanel(panel);
36311 * Get the active panel for this region.
36312 * @return {Roo.ContentPanel} The active panel or null
36314 getActivePanel : function(){
36315 return this.activePanel;
36318 validateVisibility : function(){
36319 if(this.panels.getCount() < 1){
36320 this.updateTitle(" ");
36321 this.closeBtn.hide();
36324 if(!this.isVisible()){
36331 * Adds the passed ContentPanel(s) to this region.
36332 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36333 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36335 add : function(panel)
36337 if(arguments.length > 1){
36338 for(var i = 0, len = arguments.length; i < len; i++) {
36339 this.add(arguments[i]);
36344 // if we have not been rendered yet, then we can not really do much of this..
36345 if (!this.bodyEl) {
36346 this.unrendered_panels.push(panel);
36353 if(this.hasPanel(panel)){
36354 this.showPanel(panel);
36357 panel.setRegion(this);
36358 this.panels.add(panel);
36359 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36360 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36361 // and hide them... ???
36362 this.bodyEl.dom.appendChild(panel.getEl().dom);
36363 if(panel.background !== true){
36364 this.setActivePanel(panel);
36366 this.fireEvent("paneladded", this, panel);
36373 this.initPanelAsTab(panel);
36377 if(panel.background !== true){
36378 this.tabs.activate(panel.getEl().id);
36380 this.fireEvent("paneladded", this, panel);
36385 * Hides the tab for the specified panel.
36386 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36388 hidePanel : function(panel){
36389 if(this.tabs && (panel = this.getPanel(panel))){
36390 this.tabs.hideTab(panel.getEl().id);
36395 * Unhides the tab for a previously hidden panel.
36396 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36398 unhidePanel : function(panel){
36399 if(this.tabs && (panel = this.getPanel(panel))){
36400 this.tabs.unhideTab(panel.getEl().id);
36404 clearPanels : function(){
36405 while(this.panels.getCount() > 0){
36406 this.remove(this.panels.first());
36411 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36412 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36413 * @param {Boolean} preservePanel Overrides the config preservePanel option
36414 * @return {Roo.ContentPanel} The panel that was removed
36416 remove : function(panel, preservePanel)
36418 panel = this.getPanel(panel);
36423 this.fireEvent("beforeremove", this, panel, e);
36424 if(e.cancel === true){
36427 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36428 var panelId = panel.getId();
36429 this.panels.removeKey(panelId);
36431 document.body.appendChild(panel.getEl().dom);
36434 this.tabs.removeTab(panel.getEl().id);
36435 }else if (!preservePanel){
36436 this.bodyEl.dom.removeChild(panel.getEl().dom);
36438 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36439 var p = this.panels.first();
36440 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36441 tempEl.appendChild(p.getEl().dom);
36442 this.bodyEl.update("");
36443 this.bodyEl.dom.appendChild(p.getEl().dom);
36445 this.updateTitle(p.getTitle());
36447 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36448 this.setActivePanel(p);
36450 panel.setRegion(null);
36451 if(this.activePanel == panel){
36452 this.activePanel = null;
36454 if(this.config.autoDestroy !== false && preservePanel !== true){
36455 try{panel.destroy();}catch(e){}
36457 this.fireEvent("panelremoved", this, panel);
36462 * Returns the TabPanel component used by this region
36463 * @return {Roo.TabPanel}
36465 getTabs : function(){
36469 createTool : function(parentEl, className){
36470 var btn = Roo.DomHelper.append(parentEl, {
36472 cls: "x-layout-tools-button",
36475 cls: "roo-layout-tools-button-inner " + className,
36479 btn.addClassOnOver("roo-layout-tools-button-over");
36484 * Ext JS Library 1.1.1
36485 * Copyright(c) 2006-2007, Ext JS, LLC.
36487 * Originally Released Under LGPL - original licence link has changed is not relivant.
36490 * <script type="text/javascript">
36496 * @class Roo.SplitLayoutRegion
36497 * @extends Roo.LayoutRegion
36498 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36500 Roo.bootstrap.layout.Split = function(config){
36501 this.cursor = config.cursor;
36502 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36505 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36507 splitTip : "Drag to resize.",
36508 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36509 useSplitTips : false,
36511 applyConfig : function(config){
36512 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36515 onRender : function(ctr,pos) {
36517 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36518 if(!this.config.split){
36523 var splitEl = Roo.DomHelper.append(ctr.dom, {
36525 id: this.el.id + "-split",
36526 cls: "roo-layout-split roo-layout-split-"+this.position,
36529 /** The SplitBar for this region
36530 * @type Roo.SplitBar */
36531 // does not exist yet...
36532 Roo.log([this.position, this.orientation]);
36534 this.split = new Roo.bootstrap.SplitBar({
36535 dragElement : splitEl,
36536 resizingElement: this.el,
36537 orientation : this.orientation
36540 this.split.on("moved", this.onSplitMove, this);
36541 this.split.useShim = this.config.useShim === true;
36542 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36543 if(this.useSplitTips){
36544 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36546 //if(config.collapsible){
36547 // this.split.el.on("dblclick", this.collapse, this);
36550 if(typeof this.config.minSize != "undefined"){
36551 this.split.minSize = this.config.minSize;
36553 if(typeof this.config.maxSize != "undefined"){
36554 this.split.maxSize = this.config.maxSize;
36556 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36557 this.hideSplitter();
36562 getHMaxSize : function(){
36563 var cmax = this.config.maxSize || 10000;
36564 var center = this.mgr.getRegion("center");
36565 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36568 getVMaxSize : function(){
36569 var cmax = this.config.maxSize || 10000;
36570 var center = this.mgr.getRegion("center");
36571 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36574 onSplitMove : function(split, newSize){
36575 this.fireEvent("resized", this, newSize);
36579 * Returns the {@link Roo.SplitBar} for this region.
36580 * @return {Roo.SplitBar}
36582 getSplitBar : function(){
36587 this.hideSplitter();
36588 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36591 hideSplitter : function(){
36593 this.split.el.setLocation(-2000,-2000);
36594 this.split.el.hide();
36600 this.split.el.show();
36602 Roo.bootstrap.layout.Split.superclass.show.call(this);
36605 beforeSlide: function(){
36606 if(Roo.isGecko){// firefox overflow auto bug workaround
36607 this.bodyEl.clip();
36609 this.tabs.bodyEl.clip();
36611 if(this.activePanel){
36612 this.activePanel.getEl().clip();
36614 if(this.activePanel.beforeSlide){
36615 this.activePanel.beforeSlide();
36621 afterSlide : function(){
36622 if(Roo.isGecko){// firefox overflow auto bug workaround
36623 this.bodyEl.unclip();
36625 this.tabs.bodyEl.unclip();
36627 if(this.activePanel){
36628 this.activePanel.getEl().unclip();
36629 if(this.activePanel.afterSlide){
36630 this.activePanel.afterSlide();
36636 initAutoHide : function(){
36637 if(this.autoHide !== false){
36638 if(!this.autoHideHd){
36639 var st = new Roo.util.DelayedTask(this.slideIn, this);
36640 this.autoHideHd = {
36641 "mouseout": function(e){
36642 if(!e.within(this.el, true)){
36646 "mouseover" : function(e){
36652 this.el.on(this.autoHideHd);
36656 clearAutoHide : function(){
36657 if(this.autoHide !== false){
36658 this.el.un("mouseout", this.autoHideHd.mouseout);
36659 this.el.un("mouseover", this.autoHideHd.mouseover);
36663 clearMonitor : function(){
36664 Roo.get(document).un("click", this.slideInIf, this);
36667 // these names are backwards but not changed for compat
36668 slideOut : function(){
36669 if(this.isSlid || this.el.hasActiveFx()){
36672 this.isSlid = true;
36673 if(this.collapseBtn){
36674 this.collapseBtn.hide();
36676 this.closeBtnState = this.closeBtn.getStyle('display');
36677 this.closeBtn.hide();
36679 this.stickBtn.show();
36682 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36683 this.beforeSlide();
36684 this.el.setStyle("z-index", 10001);
36685 this.el.slideIn(this.getSlideAnchor(), {
36686 callback: function(){
36688 this.initAutoHide();
36689 Roo.get(document).on("click", this.slideInIf, this);
36690 this.fireEvent("slideshow", this);
36697 afterSlideIn : function(){
36698 this.clearAutoHide();
36699 this.isSlid = false;
36700 this.clearMonitor();
36701 this.el.setStyle("z-index", "");
36702 if(this.collapseBtn){
36703 this.collapseBtn.show();
36705 this.closeBtn.setStyle('display', this.closeBtnState);
36707 this.stickBtn.hide();
36709 this.fireEvent("slidehide", this);
36712 slideIn : function(cb){
36713 if(!this.isSlid || this.el.hasActiveFx()){
36717 this.isSlid = false;
36718 this.beforeSlide();
36719 this.el.slideOut(this.getSlideAnchor(), {
36720 callback: function(){
36721 this.el.setLeftTop(-10000, -10000);
36723 this.afterSlideIn();
36731 slideInIf : function(e){
36732 if(!e.within(this.el)){
36737 animateCollapse : function(){
36738 this.beforeSlide();
36739 this.el.setStyle("z-index", 20000);
36740 var anchor = this.getSlideAnchor();
36741 this.el.slideOut(anchor, {
36742 callback : function(){
36743 this.el.setStyle("z-index", "");
36744 this.collapsedEl.slideIn(anchor, {duration:.3});
36746 this.el.setLocation(-10000,-10000);
36748 this.fireEvent("collapsed", this);
36755 animateExpand : function(){
36756 this.beforeSlide();
36757 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36758 this.el.setStyle("z-index", 20000);
36759 this.collapsedEl.hide({
36762 this.el.slideIn(this.getSlideAnchor(), {
36763 callback : function(){
36764 this.el.setStyle("z-index", "");
36767 this.split.el.show();
36769 this.fireEvent("invalidated", this);
36770 this.fireEvent("expanded", this);
36798 getAnchor : function(){
36799 return this.anchors[this.position];
36802 getCollapseAnchor : function(){
36803 return this.canchors[this.position];
36806 getSlideAnchor : function(){
36807 return this.sanchors[this.position];
36810 getAlignAdj : function(){
36811 var cm = this.cmargins;
36812 switch(this.position){
36828 getExpandAdj : function(){
36829 var c = this.collapsedEl, cm = this.cmargins;
36830 switch(this.position){
36832 return [-(cm.right+c.getWidth()+cm.left), 0];
36835 return [cm.right+c.getWidth()+cm.left, 0];
36838 return [0, -(cm.top+cm.bottom+c.getHeight())];
36841 return [0, cm.top+cm.bottom+c.getHeight()];
36847 * Ext JS Library 1.1.1
36848 * Copyright(c) 2006-2007, Ext JS, LLC.
36850 * Originally Released Under LGPL - original licence link has changed is not relivant.
36853 * <script type="text/javascript">
36856 * These classes are private internal classes
36858 Roo.bootstrap.layout.Center = function(config){
36859 config.region = "center";
36860 Roo.bootstrap.layout.Region.call(this, config);
36861 this.visible = true;
36862 this.minWidth = config.minWidth || 20;
36863 this.minHeight = config.minHeight || 20;
36866 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36868 // center panel can't be hidden
36872 // center panel can't be hidden
36875 getMinWidth: function(){
36876 return this.minWidth;
36879 getMinHeight: function(){
36880 return this.minHeight;
36893 Roo.bootstrap.layout.North = function(config)
36895 config.region = 'north';
36896 config.cursor = 'n-resize';
36898 Roo.bootstrap.layout.Split.call(this, config);
36902 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36903 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36904 this.split.el.addClass("roo-layout-split-v");
36906 var size = config.initialSize || config.height;
36907 if(typeof size != "undefined"){
36908 this.el.setHeight(size);
36911 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36913 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36917 getBox : function(){
36918 if(this.collapsed){
36919 return this.collapsedEl.getBox();
36921 var box = this.el.getBox();
36923 box.height += this.split.el.getHeight();
36928 updateBox : function(box){
36929 if(this.split && !this.collapsed){
36930 box.height -= this.split.el.getHeight();
36931 this.split.el.setLeft(box.x);
36932 this.split.el.setTop(box.y+box.height);
36933 this.split.el.setWidth(box.width);
36935 if(this.collapsed){
36936 this.updateBody(box.width, null);
36938 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36946 Roo.bootstrap.layout.South = function(config){
36947 config.region = 'south';
36948 config.cursor = 's-resize';
36949 Roo.bootstrap.layout.Split.call(this, config);
36951 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36952 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36953 this.split.el.addClass("roo-layout-split-v");
36955 var size = config.initialSize || config.height;
36956 if(typeof size != "undefined"){
36957 this.el.setHeight(size);
36961 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36962 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36963 getBox : function(){
36964 if(this.collapsed){
36965 return this.collapsedEl.getBox();
36967 var box = this.el.getBox();
36969 var sh = this.split.el.getHeight();
36976 updateBox : function(box){
36977 if(this.split && !this.collapsed){
36978 var sh = this.split.el.getHeight();
36981 this.split.el.setLeft(box.x);
36982 this.split.el.setTop(box.y-sh);
36983 this.split.el.setWidth(box.width);
36985 if(this.collapsed){
36986 this.updateBody(box.width, null);
36988 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36992 Roo.bootstrap.layout.East = function(config){
36993 config.region = "east";
36994 config.cursor = "e-resize";
36995 Roo.bootstrap.layout.Split.call(this, config);
36997 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36998 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36999 this.split.el.addClass("roo-layout-split-h");
37001 var size = config.initialSize || config.width;
37002 if(typeof size != "undefined"){
37003 this.el.setWidth(size);
37006 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37007 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37008 getBox : function(){
37009 if(this.collapsed){
37010 return this.collapsedEl.getBox();
37012 var box = this.el.getBox();
37014 var sw = this.split.el.getWidth();
37021 updateBox : function(box){
37022 if(this.split && !this.collapsed){
37023 var sw = this.split.el.getWidth();
37025 this.split.el.setLeft(box.x);
37026 this.split.el.setTop(box.y);
37027 this.split.el.setHeight(box.height);
37030 if(this.collapsed){
37031 this.updateBody(null, box.height);
37033 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37037 Roo.bootstrap.layout.West = function(config){
37038 config.region = "west";
37039 config.cursor = "w-resize";
37041 Roo.bootstrap.layout.Split.call(this, config);
37043 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37044 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37045 this.split.el.addClass("roo-layout-split-h");
37049 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37050 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37052 onRender: function(ctr, pos)
37054 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37055 var size = this.config.initialSize || this.config.width;
37056 if(typeof size != "undefined"){
37057 this.el.setWidth(size);
37061 getBox : function(){
37062 if(this.collapsed){
37063 return this.collapsedEl.getBox();
37065 var box = this.el.getBox();
37067 box.width += this.split.el.getWidth();
37072 updateBox : function(box){
37073 if(this.split && !this.collapsed){
37074 var sw = this.split.el.getWidth();
37076 this.split.el.setLeft(box.x+box.width);
37077 this.split.el.setTop(box.y);
37078 this.split.el.setHeight(box.height);
37080 if(this.collapsed){
37081 this.updateBody(null, box.height);
37083 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37086 Roo.namespace("Roo.bootstrap.panel");/*
37088 * Ext JS Library 1.1.1
37089 * Copyright(c) 2006-2007, Ext JS, LLC.
37091 * Originally Released Under LGPL - original licence link has changed is not relivant.
37094 * <script type="text/javascript">
37097 * @class Roo.ContentPanel
37098 * @extends Roo.util.Observable
37099 * A basic ContentPanel element.
37100 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37101 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37102 * @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
37103 * @cfg {Boolean} closable True if the panel can be closed/removed
37104 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37105 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37106 * @cfg {Toolbar} toolbar A toolbar for this panel
37107 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37108 * @cfg {String} title The title for this panel
37109 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37110 * @cfg {String} url Calls {@link #setUrl} with this value
37111 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37112 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37113 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37114 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37115 * @cfg {Boolean} badges render the badges
37118 * Create a new ContentPanel.
37119 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37120 * @param {String/Object} config A string to set only the title or a config object
37121 * @param {String} content (optional) Set the HTML content for this panel
37122 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37124 Roo.bootstrap.panel.Content = function( config){
37126 this.tpl = config.tpl || false;
37128 var el = config.el;
37129 var content = config.content;
37131 if(config.autoCreate){ // xtype is available if this is called from factory
37134 this.el = Roo.get(el);
37135 if(!this.el && config && config.autoCreate){
37136 if(typeof config.autoCreate == "object"){
37137 if(!config.autoCreate.id){
37138 config.autoCreate.id = config.id||el;
37140 this.el = Roo.DomHelper.append(document.body,
37141 config.autoCreate, true);
37143 var elcfg = { tag: "div",
37144 cls: "roo-layout-inactive-content",
37148 elcfg.html = config.html;
37152 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37155 this.closable = false;
37156 this.loaded = false;
37157 this.active = false;
37160 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37162 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37164 this.wrapEl = this.el; //this.el.wrap();
37166 if (config.toolbar.items) {
37167 ti = config.toolbar.items ;
37168 delete config.toolbar.items ;
37172 this.toolbar.render(this.wrapEl, 'before');
37173 for(var i =0;i < ti.length;i++) {
37174 // Roo.log(['add child', items[i]]);
37175 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37177 this.toolbar.items = nitems;
37178 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37179 delete config.toolbar;
37183 // xtype created footer. - not sure if will work as we normally have to render first..
37184 if (this.footer && !this.footer.el && this.footer.xtype) {
37185 if (!this.wrapEl) {
37186 this.wrapEl = this.el.wrap();
37189 this.footer.container = this.wrapEl.createChild();
37191 this.footer = Roo.factory(this.footer, Roo);
37196 if(typeof config == "string"){
37197 this.title = config;
37199 Roo.apply(this, config);
37203 this.resizeEl = Roo.get(this.resizeEl, true);
37205 this.resizeEl = this.el;
37207 // handle view.xtype
37215 * Fires when this panel is activated.
37216 * @param {Roo.ContentPanel} this
37220 * @event deactivate
37221 * Fires when this panel is activated.
37222 * @param {Roo.ContentPanel} this
37224 "deactivate" : true,
37228 * Fires when this panel is resized if fitToFrame is true.
37229 * @param {Roo.ContentPanel} this
37230 * @param {Number} width The width after any component adjustments
37231 * @param {Number} height The height after any component adjustments
37237 * Fires when this tab is created
37238 * @param {Roo.ContentPanel} this
37249 if(this.autoScroll){
37250 this.resizeEl.setStyle("overflow", "auto");
37252 // fix randome scrolling
37253 //this.el.on('scroll', function() {
37254 // Roo.log('fix random scolling');
37255 // this.scrollTo('top',0);
37258 content = content || this.content;
37260 this.setContent(content);
37262 if(config && config.url){
37263 this.setUrl(this.url, this.params, this.loadOnce);
37268 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37270 if (this.view && typeof(this.view.xtype) != 'undefined') {
37271 this.view.el = this.el.appendChild(document.createElement("div"));
37272 this.view = Roo.factory(this.view);
37273 this.view.render && this.view.render(false, '');
37277 this.fireEvent('render', this);
37280 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37284 setRegion : function(region){
37285 this.region = region;
37286 this.setActiveClass(region && !this.background);
37290 setActiveClass: function(state)
37293 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37294 this.el.setStyle('position','relative');
37296 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37297 this.el.setStyle('position', 'absolute');
37302 * Returns the toolbar for this Panel if one was configured.
37303 * @return {Roo.Toolbar}
37305 getToolbar : function(){
37306 return this.toolbar;
37309 setActiveState : function(active)
37311 this.active = active;
37312 this.setActiveClass(active);
37314 if(this.fireEvent("deactivate", this) === false){
37319 this.fireEvent("activate", this);
37323 * Updates this panel's element
37324 * @param {String} content The new content
37325 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37327 setContent : function(content, loadScripts){
37328 this.el.update(content, loadScripts);
37331 ignoreResize : function(w, h){
37332 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37335 this.lastSize = {width: w, height: h};
37340 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37341 * @return {Roo.UpdateManager} The UpdateManager
37343 getUpdateManager : function(){
37344 return this.el.getUpdateManager();
37347 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37348 * @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:
37351 url: "your-url.php",
37352 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37353 callback: yourFunction,
37354 scope: yourObject, //(optional scope)
37357 text: "Loading...",
37362 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37363 * 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.
37364 * @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}
37365 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37366 * @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.
37367 * @return {Roo.ContentPanel} this
37370 var um = this.el.getUpdateManager();
37371 um.update.apply(um, arguments);
37377 * 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.
37378 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37379 * @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)
37380 * @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)
37381 * @return {Roo.UpdateManager} The UpdateManager
37383 setUrl : function(url, params, loadOnce){
37384 if(this.refreshDelegate){
37385 this.removeListener("activate", this.refreshDelegate);
37387 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37388 this.on("activate", this.refreshDelegate);
37389 return this.el.getUpdateManager();
37392 _handleRefresh : function(url, params, loadOnce){
37393 if(!loadOnce || !this.loaded){
37394 var updater = this.el.getUpdateManager();
37395 updater.update(url, params, this._setLoaded.createDelegate(this));
37399 _setLoaded : function(){
37400 this.loaded = true;
37404 * Returns this panel's id
37407 getId : function(){
37412 * Returns this panel's element - used by regiosn to add.
37413 * @return {Roo.Element}
37415 getEl : function(){
37416 return this.wrapEl || this.el;
37421 adjustForComponents : function(width, height)
37423 //Roo.log('adjustForComponents ');
37424 if(this.resizeEl != this.el){
37425 width -= this.el.getFrameWidth('lr');
37426 height -= this.el.getFrameWidth('tb');
37429 var te = this.toolbar.getEl();
37430 te.setWidth(width);
37431 height -= te.getHeight();
37434 var te = this.footer.getEl();
37435 te.setWidth(width);
37436 height -= te.getHeight();
37440 if(this.adjustments){
37441 width += this.adjustments[0];
37442 height += this.adjustments[1];
37444 return {"width": width, "height": height};
37447 setSize : function(width, height){
37448 if(this.fitToFrame && !this.ignoreResize(width, height)){
37449 if(this.fitContainer && this.resizeEl != this.el){
37450 this.el.setSize(width, height);
37452 var size = this.adjustForComponents(width, height);
37453 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37454 this.fireEvent('resize', this, size.width, size.height);
37459 * Returns this panel's title
37462 getTitle : function(){
37464 if (typeof(this.title) != 'object') {
37469 for (var k in this.title) {
37470 if (!this.title.hasOwnProperty(k)) {
37474 if (k.indexOf('-') >= 0) {
37475 var s = k.split('-');
37476 for (var i = 0; i<s.length; i++) {
37477 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37480 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37487 * Set this panel's title
37488 * @param {String} title
37490 setTitle : function(title){
37491 this.title = title;
37493 this.region.updatePanelTitle(this, title);
37498 * Returns true is this panel was configured to be closable
37499 * @return {Boolean}
37501 isClosable : function(){
37502 return this.closable;
37505 beforeSlide : function(){
37507 this.resizeEl.clip();
37510 afterSlide : function(){
37512 this.resizeEl.unclip();
37516 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37517 * Will fail silently if the {@link #setUrl} method has not been called.
37518 * This does not activate the panel, just updates its content.
37520 refresh : function(){
37521 if(this.refreshDelegate){
37522 this.loaded = false;
37523 this.refreshDelegate();
37528 * Destroys this panel
37530 destroy : function(){
37531 this.el.removeAllListeners();
37532 var tempEl = document.createElement("span");
37533 tempEl.appendChild(this.el.dom);
37534 tempEl.innerHTML = "";
37540 * form - if the content panel contains a form - this is a reference to it.
37541 * @type {Roo.form.Form}
37545 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37546 * This contains a reference to it.
37552 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37562 * @param {Object} cfg Xtype definition of item to add.
37566 getChildContainer: function () {
37567 return this.getEl();
37572 var ret = new Roo.factory(cfg);
37577 if (cfg.xtype.match(/^Form$/)) {
37580 //if (this.footer) {
37581 // el = this.footer.container.insertSibling(false, 'before');
37583 el = this.el.createChild();
37586 this.form = new Roo.form.Form(cfg);
37589 if ( this.form.allItems.length) {
37590 this.form.render(el.dom);
37594 // should only have one of theses..
37595 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37596 // views.. should not be just added - used named prop 'view''
37598 cfg.el = this.el.appendChild(document.createElement("div"));
37601 var ret = new Roo.factory(cfg);
37603 ret.render && ret.render(false, ''); // render blank..
37613 * @class Roo.bootstrap.panel.Grid
37614 * @extends Roo.bootstrap.panel.Content
37616 * Create a new GridPanel.
37617 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37618 * @param {Object} config A the config object
37624 Roo.bootstrap.panel.Grid = function(config)
37628 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37629 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37631 config.el = this.wrapper;
37632 //this.el = this.wrapper;
37634 if (config.container) {
37635 // ctor'ed from a Border/panel.grid
37638 this.wrapper.setStyle("overflow", "hidden");
37639 this.wrapper.addClass('roo-grid-container');
37644 if(config.toolbar){
37645 var tool_el = this.wrapper.createChild();
37646 this.toolbar = Roo.factory(config.toolbar);
37648 if (config.toolbar.items) {
37649 ti = config.toolbar.items ;
37650 delete config.toolbar.items ;
37654 this.toolbar.render(tool_el);
37655 for(var i =0;i < ti.length;i++) {
37656 // Roo.log(['add child', items[i]]);
37657 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37659 this.toolbar.items = nitems;
37661 delete config.toolbar;
37664 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37665 config.grid.scrollBody = true;;
37666 config.grid.monitorWindowResize = false; // turn off autosizing
37667 config.grid.autoHeight = false;
37668 config.grid.autoWidth = false;
37670 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37672 if (config.background) {
37673 // render grid on panel activation (if panel background)
37674 this.on('activate', function(gp) {
37675 if (!gp.grid.rendered) {
37676 gp.grid.render(this.wrapper);
37677 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37682 this.grid.render(this.wrapper);
37683 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37686 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37687 // ??? needed ??? config.el = this.wrapper;
37692 // xtype created footer. - not sure if will work as we normally have to render first..
37693 if (this.footer && !this.footer.el && this.footer.xtype) {
37695 var ctr = this.grid.getView().getFooterPanel(true);
37696 this.footer.dataSource = this.grid.dataSource;
37697 this.footer = Roo.factory(this.footer, Roo);
37698 this.footer.render(ctr);
37708 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37709 getId : function(){
37710 return this.grid.id;
37714 * Returns the grid for this panel
37715 * @return {Roo.bootstrap.Table}
37717 getGrid : function(){
37721 setSize : function(width, height){
37722 if(!this.ignoreResize(width, height)){
37723 var grid = this.grid;
37724 var size = this.adjustForComponents(width, height);
37725 var gridel = grid.getGridEl();
37726 gridel.setSize(size.width, size.height);
37728 var thd = grid.getGridEl().select('thead',true).first();
37729 var tbd = grid.getGridEl().select('tbody', true).first();
37731 tbd.setSize(width, height - thd.getHeight());
37740 beforeSlide : function(){
37741 this.grid.getView().scroller.clip();
37744 afterSlide : function(){
37745 this.grid.getView().scroller.unclip();
37748 destroy : function(){
37749 this.grid.destroy();
37751 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37756 * @class Roo.bootstrap.panel.Nest
37757 * @extends Roo.bootstrap.panel.Content
37759 * Create a new Panel, that can contain a layout.Border.
37762 * @param {Roo.BorderLayout} layout The layout for this panel
37763 * @param {String/Object} config A string to set only the title or a config object
37765 Roo.bootstrap.panel.Nest = function(config)
37767 // construct with only one argument..
37768 /* FIXME - implement nicer consturctors
37769 if (layout.layout) {
37771 layout = config.layout;
37772 delete config.layout;
37774 if (layout.xtype && !layout.getEl) {
37775 // then layout needs constructing..
37776 layout = Roo.factory(layout, Roo);
37780 config.el = config.layout.getEl();
37782 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37784 config.layout.monitorWindowResize = false; // turn off autosizing
37785 this.layout = config.layout;
37786 this.layout.getEl().addClass("roo-layout-nested-layout");
37793 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37795 setSize : function(width, height){
37796 if(!this.ignoreResize(width, height)){
37797 var size = this.adjustForComponents(width, height);
37798 var el = this.layout.getEl();
37799 if (size.height < 1) {
37800 el.setWidth(size.width);
37802 el.setSize(size.width, size.height);
37804 var touch = el.dom.offsetWidth;
37805 this.layout.layout();
37806 // ie requires a double layout on the first pass
37807 if(Roo.isIE && !this.initialized){
37808 this.initialized = true;
37809 this.layout.layout();
37814 // activate all subpanels if not currently active..
37816 setActiveState : function(active){
37817 this.active = active;
37818 this.setActiveClass(active);
37821 this.fireEvent("deactivate", this);
37825 this.fireEvent("activate", this);
37826 // not sure if this should happen before or after..
37827 if (!this.layout) {
37828 return; // should not happen..
37831 for (var r in this.layout.regions) {
37832 reg = this.layout.getRegion(r);
37833 if (reg.getActivePanel()) {
37834 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37835 reg.setActivePanel(reg.getActivePanel());
37838 if (!reg.panels.length) {
37841 reg.showPanel(reg.getPanel(0));
37850 * Returns the nested BorderLayout for this panel
37851 * @return {Roo.BorderLayout}
37853 getLayout : function(){
37854 return this.layout;
37858 * Adds a xtype elements to the layout of the nested panel
37862 xtype : 'ContentPanel',
37869 xtype : 'NestedLayoutPanel',
37875 items : [ ... list of content panels or nested layout panels.. ]
37879 * @param {Object} cfg Xtype definition of item to add.
37881 addxtype : function(cfg) {
37882 return this.layout.addxtype(cfg);
37887 * Ext JS Library 1.1.1
37888 * Copyright(c) 2006-2007, Ext JS, LLC.
37890 * Originally Released Under LGPL - original licence link has changed is not relivant.
37893 * <script type="text/javascript">
37896 * @class Roo.TabPanel
37897 * @extends Roo.util.Observable
37898 * A lightweight tab container.
37902 // basic tabs 1, built from existing content
37903 var tabs = new Roo.TabPanel("tabs1");
37904 tabs.addTab("script", "View Script");
37905 tabs.addTab("markup", "View Markup");
37906 tabs.activate("script");
37908 // more advanced tabs, built from javascript
37909 var jtabs = new Roo.TabPanel("jtabs");
37910 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37912 // set up the UpdateManager
37913 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37914 var updater = tab2.getUpdateManager();
37915 updater.setDefaultUrl("ajax1.htm");
37916 tab2.on('activate', updater.refresh, updater, true);
37918 // Use setUrl for Ajax loading
37919 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37920 tab3.setUrl("ajax2.htm", null, true);
37923 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37926 jtabs.activate("jtabs-1");
37929 * Create a new TabPanel.
37930 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37931 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37933 Roo.bootstrap.panel.Tabs = function(config){
37935 * The container element for this TabPanel.
37936 * @type Roo.Element
37938 this.el = Roo.get(config.el);
37941 if(typeof config == "boolean"){
37942 this.tabPosition = config ? "bottom" : "top";
37944 Roo.apply(this, config);
37948 if(this.tabPosition == "bottom"){
37949 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37950 this.el.addClass("roo-tabs-bottom");
37952 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37953 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37954 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
37955 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37957 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37959 if(this.tabPosition != "bottom"){
37960 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37961 * @type Roo.Element
37963 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37964 this.el.addClass("roo-tabs-top");
37968 this.bodyEl.setStyle("position", "relative");
37970 this.active = null;
37971 this.activateDelegate = this.activate.createDelegate(this);
37976 * Fires when the active tab changes
37977 * @param {Roo.TabPanel} this
37978 * @param {Roo.TabPanelItem} activePanel The new active tab
37982 * @event beforetabchange
37983 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37984 * @param {Roo.TabPanel} this
37985 * @param {Object} e Set cancel to true on this object to cancel the tab change
37986 * @param {Roo.TabPanelItem} tab The tab being changed to
37988 "beforetabchange" : true
37991 Roo.EventManager.onWindowResize(this.onResize, this);
37992 this.cpad = this.el.getPadding("lr");
37993 this.hiddenCount = 0;
37996 // toolbar on the tabbar support...
37997 if (this.toolbar) {
37998 alert("no toolbar support yet");
37999 this.toolbar = false;
38001 var tcfg = this.toolbar;
38002 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38003 this.toolbar = new Roo.Toolbar(tcfg);
38004 if (Roo.isSafari) {
38005 var tbl = tcfg.container.child('table', true);
38006 tbl.setAttribute('width', '100%');
38014 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38017 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38019 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38021 tabPosition : "top",
38023 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38025 currentTabWidth : 0,
38027 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38031 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38035 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38037 preferredTabWidth : 175,
38039 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38041 resizeTabs : false,
38043 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38045 monitorResize : true,
38047 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38052 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38053 * @param {String} id The id of the div to use <b>or create</b>
38054 * @param {String} text The text for the tab
38055 * @param {String} content (optional) Content to put in the TabPanelItem body
38056 * @param {Boolean} closable (optional) True to create a close icon on the tab
38057 * @return {Roo.TabPanelItem} The created TabPanelItem
38059 addTab : function(id, text, content, closable, tpl)
38061 var item = new Roo.bootstrap.panel.TabItem({
38065 closable : closable,
38068 this.addTabItem(item);
38070 item.setContent(content);
38076 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38077 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38078 * @return {Roo.TabPanelItem}
38080 getTab : function(id){
38081 return this.items[id];
38085 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38086 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38088 hideTab : function(id){
38089 var t = this.items[id];
38092 this.hiddenCount++;
38093 this.autoSizeTabs();
38098 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38099 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38101 unhideTab : function(id){
38102 var t = this.items[id];
38104 t.setHidden(false);
38105 this.hiddenCount--;
38106 this.autoSizeTabs();
38111 * Adds an existing {@link Roo.TabPanelItem}.
38112 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38114 addTabItem : function(item)
38116 this.items[item.id] = item;
38117 this.items.push(item);
38118 this.autoSizeTabs();
38119 // if(this.resizeTabs){
38120 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38121 // this.autoSizeTabs();
38123 // item.autoSize();
38128 * Removes a {@link Roo.TabPanelItem}.
38129 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38131 removeTab : function(id){
38132 var items = this.items;
38133 var tab = items[id];
38134 if(!tab) { return; }
38135 var index = items.indexOf(tab);
38136 if(this.active == tab && items.length > 1){
38137 var newTab = this.getNextAvailable(index);
38142 this.stripEl.dom.removeChild(tab.pnode.dom);
38143 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38144 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38146 items.splice(index, 1);
38147 delete this.items[tab.id];
38148 tab.fireEvent("close", tab);
38149 tab.purgeListeners();
38150 this.autoSizeTabs();
38153 getNextAvailable : function(start){
38154 var items = this.items;
38156 // look for a next tab that will slide over to
38157 // replace the one being removed
38158 while(index < items.length){
38159 var item = items[++index];
38160 if(item && !item.isHidden()){
38164 // if one isn't found select the previous tab (on the left)
38167 var item = items[--index];
38168 if(item && !item.isHidden()){
38176 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38177 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38179 disableTab : function(id){
38180 var tab = this.items[id];
38181 if(tab && this.active != tab){
38187 * Enables a {@link Roo.TabPanelItem} that is disabled.
38188 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38190 enableTab : function(id){
38191 var tab = this.items[id];
38196 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38197 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38198 * @return {Roo.TabPanelItem} The TabPanelItem.
38200 activate : function(id)
38202 var tab = this.items[id];
38206 if(tab == this.active || tab.disabled){
38210 this.fireEvent("beforetabchange", this, e, tab);
38211 if(e.cancel !== true && !tab.disabled){
38213 this.active.hide();
38215 this.active = this.items[id];
38216 this.active.show();
38217 this.fireEvent("tabchange", this, this.active);
38223 * Gets the active {@link Roo.TabPanelItem}.
38224 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38226 getActiveTab : function(){
38227 return this.active;
38231 * Updates the tab body element to fit the height of the container element
38232 * for overflow scrolling
38233 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38235 syncHeight : function(targetHeight){
38236 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38237 var bm = this.bodyEl.getMargins();
38238 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38239 this.bodyEl.setHeight(newHeight);
38243 onResize : function(){
38244 if(this.monitorResize){
38245 this.autoSizeTabs();
38250 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38252 beginUpdate : function(){
38253 this.updating = true;
38257 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38259 endUpdate : function(){
38260 this.updating = false;
38261 this.autoSizeTabs();
38265 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38267 autoSizeTabs : function()
38269 var count = this.items.length;
38270 var vcount = count - this.hiddenCount;
38273 this.stripEl.hide();
38275 this.stripEl.show();
38278 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38283 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38284 var availWidth = Math.floor(w / vcount);
38285 var b = this.stripBody;
38286 if(b.getWidth() > w){
38287 var tabs = this.items;
38288 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38289 if(availWidth < this.minTabWidth){
38290 /*if(!this.sleft){ // incomplete scrolling code
38291 this.createScrollButtons();
38294 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38297 if(this.currentTabWidth < this.preferredTabWidth){
38298 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38304 * Returns the number of tabs in this TabPanel.
38307 getCount : function(){
38308 return this.items.length;
38312 * Resizes all the tabs to the passed width
38313 * @param {Number} The new width
38315 setTabWidth : function(width){
38316 this.currentTabWidth = width;
38317 for(var i = 0, len = this.items.length; i < len; i++) {
38318 if(!this.items[i].isHidden()) {
38319 this.items[i].setWidth(width);
38325 * Destroys this TabPanel
38326 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38328 destroy : function(removeEl){
38329 Roo.EventManager.removeResizeListener(this.onResize, this);
38330 for(var i = 0, len = this.items.length; i < len; i++){
38331 this.items[i].purgeListeners();
38333 if(removeEl === true){
38334 this.el.update("");
38339 createStrip : function(container)
38341 var strip = document.createElement("nav");
38342 strip.className = Roo.bootstrap.version == 4 ?
38343 "navbar-light bg-light" :
38344 "navbar navbar-default"; //"x-tabs-wrap";
38345 container.appendChild(strip);
38349 createStripList : function(strip)
38351 // div wrapper for retard IE
38352 // returns the "tr" element.
38353 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38354 //'<div class="x-tabs-strip-wrap">'+
38355 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38356 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38357 return strip.firstChild; //.firstChild.firstChild.firstChild;
38359 createBody : function(container)
38361 var body = document.createElement("div");
38362 Roo.id(body, "tab-body");
38363 //Roo.fly(body).addClass("x-tabs-body");
38364 Roo.fly(body).addClass("tab-content");
38365 container.appendChild(body);
38368 createItemBody :function(bodyEl, id){
38369 var body = Roo.getDom(id);
38371 body = document.createElement("div");
38374 //Roo.fly(body).addClass("x-tabs-item-body");
38375 Roo.fly(body).addClass("tab-pane");
38376 bodyEl.insertBefore(body, bodyEl.firstChild);
38380 createStripElements : function(stripEl, text, closable, tpl)
38382 var td = document.createElement("li"); // was td..
38383 td.className = 'nav-item';
38385 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38388 stripEl.appendChild(td);
38390 td.className = "x-tabs-closable";
38391 if(!this.closeTpl){
38392 this.closeTpl = new Roo.Template(
38393 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38394 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38395 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38398 var el = this.closeTpl.overwrite(td, {"text": text});
38399 var close = el.getElementsByTagName("div")[0];
38400 var inner = el.getElementsByTagName("em")[0];
38401 return {"el": el, "close": close, "inner": inner};
38404 // not sure what this is..
38405 // if(!this.tabTpl){
38406 //this.tabTpl = new Roo.Template(
38407 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38408 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38410 // this.tabTpl = new Roo.Template(
38411 // '<a href="#">' +
38412 // '<span unselectable="on"' +
38413 // (this.disableTooltips ? '' : ' title="{text}"') +
38414 // ' >{text}</span></a>'
38420 var template = tpl || this.tabTpl || false;
38423 template = new Roo.Template(
38424 Roo.bootstrap.version == 4 ?
38426 '<a class="nav-link" href="#" unselectable="on"' +
38427 (this.disableTooltips ? '' : ' title="{text}"') +
38430 '<a class="nav-link" href="#">' +
38431 '<span unselectable="on"' +
38432 (this.disableTooltips ? '' : ' title="{text}"') +
38433 ' >{text}</span></a>'
38438 switch (typeof(template)) {
38442 template = new Roo.Template(template);
38448 var el = template.overwrite(td, {"text": text});
38450 var inner = el.getElementsByTagName("span")[0];
38452 return {"el": el, "inner": inner};
38460 * @class Roo.TabPanelItem
38461 * @extends Roo.util.Observable
38462 * Represents an individual item (tab plus body) in a TabPanel.
38463 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38464 * @param {String} id The id of this TabPanelItem
38465 * @param {String} text The text for the tab of this TabPanelItem
38466 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38468 Roo.bootstrap.panel.TabItem = function(config){
38470 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38471 * @type Roo.TabPanel
38473 this.tabPanel = config.panel;
38475 * The id for this TabPanelItem
38478 this.id = config.id;
38480 this.disabled = false;
38482 this.text = config.text;
38484 this.loaded = false;
38485 this.closable = config.closable;
38488 * The body element for this TabPanelItem.
38489 * @type Roo.Element
38491 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38492 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38493 this.bodyEl.setStyle("display", "block");
38494 this.bodyEl.setStyle("zoom", "1");
38495 //this.hideAction();
38497 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38499 this.el = Roo.get(els.el);
38500 this.inner = Roo.get(els.inner, true);
38501 this.textEl = Roo.bootstrap.version == 4 ?
38502 this.el : Roo.get(this.el.dom.firstChild, true);
38504 this.linode = Roo.get(els.el.parentNode, true);
38505 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38508 // this.el.on("mousedown", this.onTabMouseDown, this);
38509 this.el.on("click", this.onTabClick, this);
38511 if(config.closable){
38512 var c = Roo.get(els.close, true);
38513 c.dom.title = this.closeText;
38514 c.addClassOnOver("close-over");
38515 c.on("click", this.closeClick, this);
38521 * Fires when this tab becomes the active tab.
38522 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38523 * @param {Roo.TabPanelItem} this
38527 * @event beforeclose
38528 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38529 * @param {Roo.TabPanelItem} this
38530 * @param {Object} e Set cancel to true on this object to cancel the close.
38532 "beforeclose": true,
38535 * Fires when this tab is closed.
38536 * @param {Roo.TabPanelItem} this
38540 * @event deactivate
38541 * Fires when this tab is no longer the active tab.
38542 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38543 * @param {Roo.TabPanelItem} this
38545 "deactivate" : true
38547 this.hidden = false;
38549 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38552 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38554 purgeListeners : function(){
38555 Roo.util.Observable.prototype.purgeListeners.call(this);
38556 this.el.removeAllListeners();
38559 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38562 this.status_node.addClass("active");
38565 this.tabPanel.stripWrap.repaint();
38567 this.fireEvent("activate", this.tabPanel, this);
38571 * Returns true if this tab is the active tab.
38572 * @return {Boolean}
38574 isActive : function(){
38575 return this.tabPanel.getActiveTab() == this;
38579 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38582 this.status_node.removeClass("active");
38584 this.fireEvent("deactivate", this.tabPanel, this);
38587 hideAction : function(){
38588 this.bodyEl.hide();
38589 this.bodyEl.setStyle("position", "absolute");
38590 this.bodyEl.setLeft("-20000px");
38591 this.bodyEl.setTop("-20000px");
38594 showAction : function(){
38595 this.bodyEl.setStyle("position", "relative");
38596 this.bodyEl.setTop("");
38597 this.bodyEl.setLeft("");
38598 this.bodyEl.show();
38602 * Set the tooltip for the tab.
38603 * @param {String} tooltip The tab's tooltip
38605 setTooltip : function(text){
38606 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38607 this.textEl.dom.qtip = text;
38608 this.textEl.dom.removeAttribute('title');
38610 this.textEl.dom.title = text;
38614 onTabClick : function(e){
38615 e.preventDefault();
38616 this.tabPanel.activate(this.id);
38619 onTabMouseDown : function(e){
38620 e.preventDefault();
38621 this.tabPanel.activate(this.id);
38624 getWidth : function(){
38625 return this.inner.getWidth();
38628 setWidth : function(width){
38629 var iwidth = width - this.linode.getPadding("lr");
38630 this.inner.setWidth(iwidth);
38631 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38632 this.linode.setWidth(width);
38636 * Show or hide the tab
38637 * @param {Boolean} hidden True to hide or false to show.
38639 setHidden : function(hidden){
38640 this.hidden = hidden;
38641 this.linode.setStyle("display", hidden ? "none" : "");
38645 * Returns true if this tab is "hidden"
38646 * @return {Boolean}
38648 isHidden : function(){
38649 return this.hidden;
38653 * Returns the text for this tab
38656 getText : function(){
38660 autoSize : function(){
38661 //this.el.beginMeasure();
38662 this.textEl.setWidth(1);
38664 * #2804 [new] Tabs in Roojs
38665 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38667 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38668 //this.el.endMeasure();
38672 * Sets the text for the tab (Note: this also sets the tooltip text)
38673 * @param {String} text The tab's text and tooltip
38675 setText : function(text){
38677 this.textEl.update(text);
38678 this.setTooltip(text);
38679 //if(!this.tabPanel.resizeTabs){
38680 // this.autoSize();
38684 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38686 activate : function(){
38687 this.tabPanel.activate(this.id);
38691 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38693 disable : function(){
38694 if(this.tabPanel.active != this){
38695 this.disabled = true;
38696 this.status_node.addClass("disabled");
38701 * Enables this TabPanelItem if it was previously disabled.
38703 enable : function(){
38704 this.disabled = false;
38705 this.status_node.removeClass("disabled");
38709 * Sets the content for this TabPanelItem.
38710 * @param {String} content The content
38711 * @param {Boolean} loadScripts true to look for and load scripts
38713 setContent : function(content, loadScripts){
38714 this.bodyEl.update(content, loadScripts);
38718 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38719 * @return {Roo.UpdateManager} The UpdateManager
38721 getUpdateManager : function(){
38722 return this.bodyEl.getUpdateManager();
38726 * Set a URL to be used to load the content for this TabPanelItem.
38727 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38728 * @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)
38729 * @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)
38730 * @return {Roo.UpdateManager} The UpdateManager
38732 setUrl : function(url, params, loadOnce){
38733 if(this.refreshDelegate){
38734 this.un('activate', this.refreshDelegate);
38736 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38737 this.on("activate", this.refreshDelegate);
38738 return this.bodyEl.getUpdateManager();
38742 _handleRefresh : function(url, params, loadOnce){
38743 if(!loadOnce || !this.loaded){
38744 var updater = this.bodyEl.getUpdateManager();
38745 updater.update(url, params, this._setLoaded.createDelegate(this));
38750 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38751 * Will fail silently if the setUrl method has not been called.
38752 * This does not activate the panel, just updates its content.
38754 refresh : function(){
38755 if(this.refreshDelegate){
38756 this.loaded = false;
38757 this.refreshDelegate();
38762 _setLoaded : function(){
38763 this.loaded = true;
38767 closeClick : function(e){
38770 this.fireEvent("beforeclose", this, o);
38771 if(o.cancel !== true){
38772 this.tabPanel.removeTab(this.id);
38776 * The text displayed in the tooltip for the close icon.
38779 closeText : "Close this tab"
38782 * This script refer to:
38783 * Title: International Telephone Input
38784 * Author: Jack O'Connor
38785 * Code version: v12.1.12
38786 * Availability: https://github.com/jackocnr/intl-tel-input.git
38789 Roo.bootstrap.PhoneInputData = function() {
38792 "Afghanistan (افغانستان)",
38797 "Albania (Shqipëri)",
38802 "Algeria (الجزائر)",
38827 "Antigua and Barbuda",
38837 "Armenia (Հայաստան)",
38853 "Austria (Österreich)",
38858 "Azerbaijan (Azərbaycan)",
38868 "Bahrain (البحرين)",
38873 "Bangladesh (বাংলাদেশ)",
38883 "Belarus (Беларусь)",
38888 "Belgium (België)",
38918 "Bosnia and Herzegovina (Босна и Херцеговина)",
38933 "British Indian Ocean Territory",
38938 "British Virgin Islands",
38948 "Bulgaria (България)",
38958 "Burundi (Uburundi)",
38963 "Cambodia (កម្ពុជា)",
38968 "Cameroon (Cameroun)",
38977 ["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"]
38980 "Cape Verde (Kabu Verdi)",
38985 "Caribbean Netherlands",
38996 "Central African Republic (République centrafricaine)",
39016 "Christmas Island",
39022 "Cocos (Keeling) Islands",
39033 "Comoros (جزر القمر)",
39038 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39043 "Congo (Republic) (Congo-Brazzaville)",
39063 "Croatia (Hrvatska)",
39084 "Czech Republic (Česká republika)",
39089 "Denmark (Danmark)",
39104 "Dominican Republic (República Dominicana)",
39108 ["809", "829", "849"]
39126 "Equatorial Guinea (Guinea Ecuatorial)",
39146 "Falkland Islands (Islas Malvinas)",
39151 "Faroe Islands (Føroyar)",
39172 "French Guiana (Guyane française)",
39177 "French Polynesia (Polynésie française)",
39192 "Georgia (საქართველო)",
39197 "Germany (Deutschland)",
39217 "Greenland (Kalaallit Nunaat)",
39254 "Guinea-Bissau (Guiné Bissau)",
39279 "Hungary (Magyarország)",
39284 "Iceland (Ísland)",
39304 "Iraq (العراق)",
39320 "Israel (ישראל)",
39347 "Jordan (الأردن)",
39352 "Kazakhstan (Казахстан)",
39373 "Kuwait (الكويت)",
39378 "Kyrgyzstan (Кыргызстан)",
39388 "Latvia (Latvija)",
39393 "Lebanon (لبنان)",
39408 "Libya (ليبيا)",
39418 "Lithuania (Lietuva)",
39433 "Macedonia (FYROM) (Македонија)",
39438 "Madagascar (Madagasikara)",
39468 "Marshall Islands",
39478 "Mauritania (موريتانيا)",
39483 "Mauritius (Moris)",
39504 "Moldova (Republica Moldova)",
39514 "Mongolia (Монгол)",
39519 "Montenegro (Crna Gora)",
39529 "Morocco (المغرب)",
39535 "Mozambique (Moçambique)",
39540 "Myanmar (Burma) (မြန်မာ)",
39545 "Namibia (Namibië)",
39560 "Netherlands (Nederland)",
39565 "New Caledonia (Nouvelle-Calédonie)",
39600 "North Korea (조선 민주주의 인민 공화국)",
39605 "Northern Mariana Islands",
39621 "Pakistan (پاکستان)",
39631 "Palestine (فلسطين)",
39641 "Papua New Guinea",
39683 "Réunion (La Réunion)",
39689 "Romania (România)",
39705 "Saint Barthélemy",
39716 "Saint Kitts and Nevis",
39726 "Saint Martin (Saint-Martin (partie française))",
39732 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39737 "Saint Vincent and the Grenadines",
39752 "São Tomé and Príncipe (São Tomé e Príncipe)",
39757 "Saudi Arabia (المملكة العربية السعودية)",
39762 "Senegal (Sénégal)",
39792 "Slovakia (Slovensko)",
39797 "Slovenia (Slovenija)",
39807 "Somalia (Soomaaliya)",
39817 "South Korea (대한민국)",
39822 "South Sudan (جنوب السودان)",
39832 "Sri Lanka (ශ්රී ලංකාව)",
39837 "Sudan (السودان)",
39847 "Svalbard and Jan Mayen",
39858 "Sweden (Sverige)",
39863 "Switzerland (Schweiz)",
39868 "Syria (سوريا)",
39913 "Trinidad and Tobago",
39918 "Tunisia (تونس)",
39923 "Turkey (Türkiye)",
39933 "Turks and Caicos Islands",
39943 "U.S. Virgin Islands",
39953 "Ukraine (Україна)",
39958 "United Arab Emirates (الإمارات العربية المتحدة)",
39980 "Uzbekistan (Oʻzbekiston)",
39990 "Vatican City (Città del Vaticano)",
40001 "Vietnam (Việt Nam)",
40006 "Wallis and Futuna (Wallis-et-Futuna)",
40011 "Western Sahara (الصحراء الغربية)",
40017 "Yemen (اليمن)",
40041 * This script refer to:
40042 * Title: International Telephone Input
40043 * Author: Jack O'Connor
40044 * Code version: v12.1.12
40045 * Availability: https://github.com/jackocnr/intl-tel-input.git
40049 * @class Roo.bootstrap.PhoneInput
40050 * @extends Roo.bootstrap.TriggerField
40051 * An input with International dial-code selection
40053 * @cfg {String} defaultDialCode default '+852'
40054 * @cfg {Array} preferedCountries default []
40057 * Create a new PhoneInput.
40058 * @param {Object} config Configuration options
40061 Roo.bootstrap.PhoneInput = function(config) {
40062 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40065 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40067 listWidth: undefined,
40069 selectedClass: 'active',
40071 invalidClass : "has-warning",
40073 validClass: 'has-success',
40075 allowed: '0123456789',
40080 * @cfg {String} defaultDialCode The default dial code when initializing the input
40082 defaultDialCode: '+852',
40085 * @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
40087 preferedCountries: false,
40089 getAutoCreate : function()
40091 var data = Roo.bootstrap.PhoneInputData();
40092 var align = this.labelAlign || this.parentLabelAlign();
40095 this.allCountries = [];
40096 this.dialCodeMapping = [];
40098 for (var i = 0; i < data.length; i++) {
40100 this.allCountries[i] = {
40104 priority: c[3] || 0,
40105 areaCodes: c[4] || null
40107 this.dialCodeMapping[c[2]] = {
40110 priority: c[3] || 0,
40111 areaCodes: c[4] || null
40123 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40124 maxlength: this.max_length,
40125 cls : 'form-control tel-input',
40126 autocomplete: 'new-password'
40129 var hiddenInput = {
40132 cls: 'hidden-tel-input'
40136 hiddenInput.name = this.name;
40139 if (this.disabled) {
40140 input.disabled = true;
40143 var flag_container = {
40160 cls: this.hasFeedback ? 'has-feedback' : '',
40166 cls: 'dial-code-holder',
40173 cls: 'roo-select2-container input-group',
40180 if (this.fieldLabel.length) {
40183 tooltip: 'This field is required'
40189 cls: 'control-label',
40195 html: this.fieldLabel
40198 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40204 if(this.indicatorpos == 'right') {
40205 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40212 if(align == 'left') {
40220 if(this.labelWidth > 12){
40221 label.style = "width: " + this.labelWidth + 'px';
40223 if(this.labelWidth < 13 && this.labelmd == 0){
40224 this.labelmd = this.labelWidth;
40226 if(this.labellg > 0){
40227 label.cls += ' col-lg-' + this.labellg;
40228 input.cls += ' col-lg-' + (12 - this.labellg);
40230 if(this.labelmd > 0){
40231 label.cls += ' col-md-' + this.labelmd;
40232 container.cls += ' col-md-' + (12 - this.labelmd);
40234 if(this.labelsm > 0){
40235 label.cls += ' col-sm-' + this.labelsm;
40236 container.cls += ' col-sm-' + (12 - this.labelsm);
40238 if(this.labelxs > 0){
40239 label.cls += ' col-xs-' + this.labelxs;
40240 container.cls += ' col-xs-' + (12 - this.labelxs);
40250 var settings = this;
40252 ['xs','sm','md','lg'].map(function(size){
40253 if (settings[size]) {
40254 cfg.cls += ' col-' + size + '-' + settings[size];
40258 this.store = new Roo.data.Store({
40259 proxy : new Roo.data.MemoryProxy({}),
40260 reader : new Roo.data.JsonReader({
40271 'name' : 'dialCode',
40275 'name' : 'priority',
40279 'name' : 'areaCodes',
40286 if(!this.preferedCountries) {
40287 this.preferedCountries = [
40294 var p = this.preferedCountries.reverse();
40297 for (var i = 0; i < p.length; i++) {
40298 for (var j = 0; j < this.allCountries.length; j++) {
40299 if(this.allCountries[j].iso2 == p[i]) {
40300 var t = this.allCountries[j];
40301 this.allCountries.splice(j,1);
40302 this.allCountries.unshift(t);
40308 this.store.proxy.data = {
40310 data: this.allCountries
40316 initEvents : function()
40319 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40321 this.indicator = this.indicatorEl();
40322 this.flag = this.flagEl();
40323 this.dialCodeHolder = this.dialCodeHolderEl();
40325 this.trigger = this.el.select('div.flag-box',true).first();
40326 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40331 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40332 _this.list.setWidth(lw);
40335 this.list.on('mouseover', this.onViewOver, this);
40336 this.list.on('mousemove', this.onViewMove, this);
40337 this.inputEl().on("keyup", this.onKeyUp, this);
40338 this.inputEl().on("keypress", this.onKeyPress, this);
40340 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40342 this.view = new Roo.View(this.list, this.tpl, {
40343 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40346 this.view.on('click', this.onViewClick, this);
40347 this.setValue(this.defaultDialCode);
40350 onTriggerClick : function(e)
40352 Roo.log('trigger click');
40357 if(this.isExpanded()){
40359 this.hasFocus = false;
40361 this.store.load({});
40362 this.hasFocus = true;
40367 isExpanded : function()
40369 return this.list.isVisible();
40372 collapse : function()
40374 if(!this.isExpanded()){
40378 Roo.get(document).un('mousedown', this.collapseIf, this);
40379 Roo.get(document).un('mousewheel', this.collapseIf, this);
40380 this.fireEvent('collapse', this);
40384 expand : function()
40388 if(this.isExpanded() || !this.hasFocus){
40392 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40393 this.list.setWidth(lw);
40396 this.restrictHeight();
40398 Roo.get(document).on('mousedown', this.collapseIf, this);
40399 Roo.get(document).on('mousewheel', this.collapseIf, this);
40401 this.fireEvent('expand', this);
40404 restrictHeight : function()
40406 this.list.alignTo(this.inputEl(), this.listAlign);
40407 this.list.alignTo(this.inputEl(), this.listAlign);
40410 onViewOver : function(e, t)
40412 if(this.inKeyMode){
40415 var item = this.view.findItemFromChild(t);
40418 var index = this.view.indexOf(item);
40419 this.select(index, false);
40424 onViewClick : function(view, doFocus, el, e)
40426 var index = this.view.getSelectedIndexes()[0];
40428 var r = this.store.getAt(index);
40431 this.onSelect(r, index);
40433 if(doFocus !== false && !this.blockFocus){
40434 this.inputEl().focus();
40438 onViewMove : function(e, t)
40440 this.inKeyMode = false;
40443 select : function(index, scrollIntoView)
40445 this.selectedIndex = index;
40446 this.view.select(index);
40447 if(scrollIntoView !== false){
40448 var el = this.view.getNode(index);
40450 this.list.scrollChildIntoView(el, false);
40455 createList : function()
40457 this.list = Roo.get(document.body).createChild({
40459 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40460 style: 'display:none'
40463 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40466 collapseIf : function(e)
40468 var in_combo = e.within(this.el);
40469 var in_list = e.within(this.list);
40470 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40472 if (in_combo || in_list || is_list) {
40478 onSelect : function(record, index)
40480 if(this.fireEvent('beforeselect', this, record, index) !== false){
40482 this.setFlagClass(record.data.iso2);
40483 this.setDialCode(record.data.dialCode);
40484 this.hasFocus = false;
40486 this.fireEvent('select', this, record, index);
40490 flagEl : function()
40492 var flag = this.el.select('div.flag',true).first();
40499 dialCodeHolderEl : function()
40501 var d = this.el.select('input.dial-code-holder',true).first();
40508 setDialCode : function(v)
40510 this.dialCodeHolder.dom.value = '+'+v;
40513 setFlagClass : function(n)
40515 this.flag.dom.className = 'flag '+n;
40518 getValue : function()
40520 var v = this.inputEl().getValue();
40521 if(this.dialCodeHolder) {
40522 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40527 setValue : function(v)
40529 var d = this.getDialCode(v);
40531 //invalid dial code
40532 if(v.length == 0 || !d || d.length == 0) {
40534 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40535 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40541 this.setFlagClass(this.dialCodeMapping[d].iso2);
40542 this.setDialCode(d);
40543 this.inputEl().dom.value = v.replace('+'+d,'');
40544 this.hiddenEl().dom.value = this.getValue();
40549 getDialCode : function(v)
40553 if (v.length == 0) {
40554 return this.dialCodeHolder.dom.value;
40558 if (v.charAt(0) != "+") {
40561 var numericChars = "";
40562 for (var i = 1; i < v.length; i++) {
40563 var c = v.charAt(i);
40566 if (this.dialCodeMapping[numericChars]) {
40567 dialCode = v.substr(1, i);
40569 if (numericChars.length == 4) {
40579 this.setValue(this.defaultDialCode);
40583 hiddenEl : function()
40585 return this.el.select('input.hidden-tel-input',true).first();
40588 // after setting val
40589 onKeyUp : function(e){
40590 this.setValue(this.getValue());
40593 onKeyPress : function(e){
40594 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40601 * @class Roo.bootstrap.MoneyField
40602 * @extends Roo.bootstrap.ComboBox
40603 * Bootstrap MoneyField class
40606 * Create a new MoneyField.
40607 * @param {Object} config Configuration options
40610 Roo.bootstrap.MoneyField = function(config) {
40612 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40616 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40619 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40621 allowDecimals : true,
40623 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40625 decimalSeparator : ".",
40627 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40629 decimalPrecision : 0,
40631 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40633 allowNegative : true,
40635 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40639 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40641 minValue : Number.NEGATIVE_INFINITY,
40643 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40645 maxValue : Number.MAX_VALUE,
40647 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40649 minText : "The minimum value for this field is {0}",
40651 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40653 maxText : "The maximum value for this field is {0}",
40655 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40656 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40658 nanText : "{0} is not a valid number",
40660 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40664 * @cfg {String} defaults currency of the MoneyField
40665 * value should be in lkey
40667 defaultCurrency : false,
40669 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40671 thousandsDelimiter : false,
40673 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40684 getAutoCreate : function()
40686 var align = this.labelAlign || this.parentLabelAlign();
40698 cls : 'form-control roo-money-amount-input',
40699 autocomplete: 'new-password'
40702 var hiddenInput = {
40706 cls: 'hidden-number-input'
40709 if(this.max_length) {
40710 input.maxlength = this.max_length;
40714 hiddenInput.name = this.name;
40717 if (this.disabled) {
40718 input.disabled = true;
40721 var clg = 12 - this.inputlg;
40722 var cmd = 12 - this.inputmd;
40723 var csm = 12 - this.inputsm;
40724 var cxs = 12 - this.inputxs;
40728 cls : 'row roo-money-field',
40732 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40736 cls: 'roo-select2-container input-group',
40740 cls : 'form-control roo-money-currency-input',
40741 autocomplete: 'new-password',
40743 name : this.currencyName
40747 cls : 'input-group-addon',
40761 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40765 cls: this.hasFeedback ? 'has-feedback' : '',
40776 if (this.fieldLabel.length) {
40779 tooltip: 'This field is required'
40785 cls: 'control-label',
40791 html: this.fieldLabel
40794 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40800 if(this.indicatorpos == 'right') {
40801 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40808 if(align == 'left') {
40816 if(this.labelWidth > 12){
40817 label.style = "width: " + this.labelWidth + 'px';
40819 if(this.labelWidth < 13 && this.labelmd == 0){
40820 this.labelmd = this.labelWidth;
40822 if(this.labellg > 0){
40823 label.cls += ' col-lg-' + this.labellg;
40824 input.cls += ' col-lg-' + (12 - this.labellg);
40826 if(this.labelmd > 0){
40827 label.cls += ' col-md-' + this.labelmd;
40828 container.cls += ' col-md-' + (12 - this.labelmd);
40830 if(this.labelsm > 0){
40831 label.cls += ' col-sm-' + this.labelsm;
40832 container.cls += ' col-sm-' + (12 - this.labelsm);
40834 if(this.labelxs > 0){
40835 label.cls += ' col-xs-' + this.labelxs;
40836 container.cls += ' col-xs-' + (12 - this.labelxs);
40847 var settings = this;
40849 ['xs','sm','md','lg'].map(function(size){
40850 if (settings[size]) {
40851 cfg.cls += ' col-' + size + '-' + settings[size];
40858 initEvents : function()
40860 this.indicator = this.indicatorEl();
40862 this.initCurrencyEvent();
40864 this.initNumberEvent();
40867 initCurrencyEvent : function()
40870 throw "can not find store for combo";
40873 this.store = Roo.factory(this.store, Roo.data);
40874 this.store.parent = this;
40878 this.triggerEl = this.el.select('.input-group-addon', true).first();
40880 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40885 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40886 _this.list.setWidth(lw);
40889 this.list.on('mouseover', this.onViewOver, this);
40890 this.list.on('mousemove', this.onViewMove, this);
40891 this.list.on('scroll', this.onViewScroll, this);
40894 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40897 this.view = new Roo.View(this.list, this.tpl, {
40898 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40901 this.view.on('click', this.onViewClick, this);
40903 this.store.on('beforeload', this.onBeforeLoad, this);
40904 this.store.on('load', this.onLoad, this);
40905 this.store.on('loadexception', this.onLoadException, this);
40907 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40908 "up" : function(e){
40909 this.inKeyMode = true;
40913 "down" : function(e){
40914 if(!this.isExpanded()){
40915 this.onTriggerClick();
40917 this.inKeyMode = true;
40922 "enter" : function(e){
40925 if(this.fireEvent("specialkey", this, e)){
40926 this.onViewClick(false);
40932 "esc" : function(e){
40936 "tab" : function(e){
40939 if(this.fireEvent("specialkey", this, e)){
40940 this.onViewClick(false);
40948 doRelay : function(foo, bar, hname){
40949 if(hname == 'down' || this.scope.isExpanded()){
40950 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40958 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40962 initNumberEvent : function(e)
40964 this.inputEl().on("keydown" , this.fireKey, this);
40965 this.inputEl().on("focus", this.onFocus, this);
40966 this.inputEl().on("blur", this.onBlur, this);
40968 this.inputEl().relayEvent('keyup', this);
40970 if(this.indicator){
40971 this.indicator.addClass('invisible');
40974 this.originalValue = this.getValue();
40976 if(this.validationEvent == 'keyup'){
40977 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40978 this.inputEl().on('keyup', this.filterValidation, this);
40980 else if(this.validationEvent !== false){
40981 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40984 if(this.selectOnFocus){
40985 this.on("focus", this.preFocus, this);
40988 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40989 this.inputEl().on("keypress", this.filterKeys, this);
40991 this.inputEl().relayEvent('keypress', this);
40994 var allowed = "0123456789";
40996 if(this.allowDecimals){
40997 allowed += this.decimalSeparator;
41000 if(this.allowNegative){
41004 if(this.thousandsDelimiter) {
41008 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41010 var keyPress = function(e){
41012 var k = e.getKey();
41014 var c = e.getCharCode();
41017 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41018 allowed.indexOf(String.fromCharCode(c)) === -1
41024 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41028 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41033 this.inputEl().on("keypress", keyPress, this);
41037 onTriggerClick : function(e)
41044 this.loadNext = false;
41046 if(this.isExpanded()){
41051 this.hasFocus = true;
41053 if(this.triggerAction == 'all') {
41054 this.doQuery(this.allQuery, true);
41058 this.doQuery(this.getRawValue());
41061 getCurrency : function()
41063 var v = this.currencyEl().getValue();
41068 restrictHeight : function()
41070 this.list.alignTo(this.currencyEl(), this.listAlign);
41071 this.list.alignTo(this.currencyEl(), this.listAlign);
41074 onViewClick : function(view, doFocus, el, e)
41076 var index = this.view.getSelectedIndexes()[0];
41078 var r = this.store.getAt(index);
41081 this.onSelect(r, index);
41085 onSelect : function(record, index){
41087 if(this.fireEvent('beforeselect', this, record, index) !== false){
41089 this.setFromCurrencyData(index > -1 ? record.data : false);
41093 this.fireEvent('select', this, record, index);
41097 setFromCurrencyData : function(o)
41101 this.lastCurrency = o;
41103 if (this.currencyField) {
41104 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41106 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41109 this.lastSelectionText = currency;
41111 //setting default currency
41112 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41113 this.setCurrency(this.defaultCurrency);
41117 this.setCurrency(currency);
41120 setFromData : function(o)
41124 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41126 this.setFromCurrencyData(c);
41131 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41133 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41136 this.setValue(value);
41140 setCurrency : function(v)
41142 this.currencyValue = v;
41145 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41150 setValue : function(v)
41152 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41158 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41160 this.inputEl().dom.value = (v == '') ? '' :
41161 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41163 if(!this.allowZero && v === '0') {
41164 this.hiddenEl().dom.value = '';
41165 this.inputEl().dom.value = '';
41172 getRawValue : function()
41174 var v = this.inputEl().getValue();
41179 getValue : function()
41181 return this.fixPrecision(this.parseValue(this.getRawValue()));
41184 parseValue : function(value)
41186 if(this.thousandsDelimiter) {
41188 r = new RegExp(",", "g");
41189 value = value.replace(r, "");
41192 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41193 return isNaN(value) ? '' : value;
41197 fixPrecision : function(value)
41199 if(this.thousandsDelimiter) {
41201 r = new RegExp(",", "g");
41202 value = value.replace(r, "");
41205 var nan = isNaN(value);
41207 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41208 return nan ? '' : value;
41210 return parseFloat(value).toFixed(this.decimalPrecision);
41213 decimalPrecisionFcn : function(v)
41215 return Math.floor(v);
41218 validateValue : function(value)
41220 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41224 var num = this.parseValue(value);
41227 this.markInvalid(String.format(this.nanText, value));
41231 if(num < this.minValue){
41232 this.markInvalid(String.format(this.minText, this.minValue));
41236 if(num > this.maxValue){
41237 this.markInvalid(String.format(this.maxText, this.maxValue));
41244 validate : function()
41246 if(this.disabled || this.allowBlank){
41251 var currency = this.getCurrency();
41253 if(this.validateValue(this.getRawValue()) && currency.length){
41258 this.markInvalid();
41262 getName: function()
41267 beforeBlur : function()
41273 var v = this.parseValue(this.getRawValue());
41280 onBlur : function()
41284 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41285 //this.el.removeClass(this.focusClass);
41288 this.hasFocus = false;
41290 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41294 var v = this.getValue();
41296 if(String(v) !== String(this.startValue)){
41297 this.fireEvent('change', this, v, this.startValue);
41300 this.fireEvent("blur", this);
41303 inputEl : function()
41305 return this.el.select('.roo-money-amount-input', true).first();
41308 currencyEl : function()
41310 return this.el.select('.roo-money-currency-input', true).first();
41313 hiddenEl : function()
41315 return this.el.select('input.hidden-number-input',true).first();