2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets[0], function(s) {
10 if (s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 addxtype : function(tree,cntr)
179 cn = Roo.factory(tree);
180 //Roo.log(['addxtype', cn]);
182 cn.parentType = this.xtype; //??
183 cn.parentId = this.id;
185 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 if (typeof(cn.container_method) == 'string') {
187 cntr = cn.container_method;
191 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
193 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
195 var build_from_html = Roo.XComponent.build_from_html;
197 var is_body = (tree.xtype == 'Body') ;
199 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
201 var self_cntr_el = Roo.get(this[cntr](false));
203 // do not try and build conditional elements
204 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
208 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
209 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
210 return this.addxtypeChild(tree,cntr, is_body);
213 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
216 return this.addxtypeChild(Roo.apply({}, tree),cntr);
219 Roo.log('skipping render');
225 if (!build_from_html) {
229 // this i think handles overlaying multiple children of the same type
230 // with the sam eelement.. - which might be buggy..
232 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
238 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
242 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
249 addxtypeChild : function (tree, cntr, is_body)
251 Roo.debug && Roo.log('addxtypeChild:' + cntr);
253 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
256 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
257 (typeof(tree['flexy:foreach']) != 'undefined');
261 skip_children = false;
262 // render the element if it's not BODY.
265 // if parent was disabled, then do not try and create the children..
266 if(!this[cntr](true)){
271 cn = Roo.factory(tree);
273 cn.parentType = this.xtype; //??
274 cn.parentId = this.id;
276 var build_from_html = Roo.XComponent.build_from_html;
279 // does the container contain child eleemnts with 'xtype' attributes.
280 // that match this xtype..
281 // note - when we render we create these as well..
282 // so we should check to see if body has xtype set.
283 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
285 var self_cntr_el = Roo.get(this[cntr](false));
286 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
288 //Roo.log(Roo.XComponent.build_from_html);
289 //Roo.log("got echild:");
292 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
293 // and are not displayed -this causes this to use up the wrong element when matching.
294 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
297 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
298 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
304 //echild.dom.removeAttribute('xtype');
306 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
307 Roo.debug && Roo.log(self_cntr_el);
308 Roo.debug && Roo.log(echild);
309 Roo.debug && Roo.log(cn);
315 // if object has flexy:if - then it may or may not be rendered.
316 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
317 // skip a flexy if element.
318 Roo.debug && Roo.log('skipping render');
319 Roo.debug && Roo.log(tree);
321 Roo.debug && Roo.log('skipping all children');
322 skip_children = true;
327 // actually if flexy:foreach is found, we really want to create
328 // multiple copies here...
330 //Roo.log(this[cntr]());
331 // some elements do not have render methods.. like the layouts...
333 if(this[cntr](true) === false){
338 cn.render && cn.render(this[cntr](true));
341 // then add the element..
348 if (typeof (tree.menu) != 'undefined') {
349 tree.menu.parentType = cn.xtype;
350 tree.menu.triggerEl = cn.el;
351 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
355 if (!tree.items || !tree.items.length) {
357 //Roo.log(["no children", this]);
362 var items = tree.items;
365 //Roo.log(items.length);
367 if (!skip_children) {
368 for(var i =0;i < items.length;i++) {
369 // Roo.log(['add child', items[i]]);
370 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
376 //Roo.log("fire childrenrendered");
378 cn.fireEvent('childrenrendered', this);
384 * Set the element that will be used to show or hide
386 setVisibilityEl : function(el)
388 this.visibilityEl = el;
392 * Get the element that will be used to show or hide
394 getVisibilityEl : function()
396 if (typeof(this.visibilityEl) == 'object') {
397 return this.visibilityEl;
400 if (typeof(this.visibilityEl) == 'string') {
401 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
408 * Show a component - removes 'hidden' class
412 if(!this.getVisibilityEl()){
416 this.getVisibilityEl().removeClass(['hidden','d-none']);
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass(['hidden','d-none']);
433 this.fireEvent('hide', this);
446 * @class Roo.bootstrap.Body
447 * @extends Roo.bootstrap.Component
448 * Bootstrap Body class
452 * @param {Object} config The config object
455 Roo.bootstrap.Body = function(config){
457 config = config || {};
459 Roo.bootstrap.Body.superclass.constructor.call(this, config);
460 this.el = Roo.get(config.el ? config.el : document.body );
461 if (this.cls && this.cls.length) {
462 Roo.get(document.body).addClass(this.cls);
466 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
468 is_body : true,// just to make sure it's constructed?
473 onRender : function(ct, position)
475 /* Roo.log("Roo.bootstrap.Body - onRender");
476 if (this.cls && this.cls.length) {
477 Roo.get(document.body).addClass(this.cls);
496 * @class Roo.bootstrap.ButtonGroup
497 * @extends Roo.bootstrap.Component
498 * Bootstrap ButtonGroup class
499 * @cfg {String} size lg | sm | xs (default empty normal)
500 * @cfg {String} align vertical | justified (default none)
501 * @cfg {String} direction up | down (default down)
502 * @cfg {Boolean} toolbar false | true
503 * @cfg {Boolean} btn true | false
508 * @param {Object} config The config object
511 Roo.bootstrap.ButtonGroup = function(config){
512 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
515 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
523 getAutoCreate : function(){
529 cfg.html = this.html || cfg.html;
540 if (['vertical','justified'].indexOf(this.align)!==-1) {
541 cfg.cls = 'btn-group-' + this.align;
543 if (this.align == 'justified') {
544 console.log(this.items);
548 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
549 cfg.cls += ' btn-group-' + this.size;
552 if (this.direction == 'up') {
553 cfg.cls += ' dropup' ;
559 * Add a button to the group (similar to NavItem API.)
561 addItem : function(cfg)
563 var cn = new Roo.bootstrap.Button(cfg);
565 cn.parentId = this.id;
566 cn.onRender(this.el, null);
580 * @class Roo.bootstrap.Button
581 * @extends Roo.bootstrap.Component
582 * Bootstrap Button class
583 * @cfg {String} html The button content
584 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
585 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
586 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
587 * @cfg {String} size ( lg | sm | xs)
588 * @cfg {String} tag ( a | input | submit)
589 * @cfg {String} href empty or href
590 * @cfg {Boolean} disabled default false;
591 * @cfg {Boolean} isClose default false;
592 * @cfg {String} glyphicon depricated - use fa
593 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
594 * @cfg {String} badge text for badge
595 * @cfg {String} theme (default|glow)
596 * @cfg {Boolean} inverse dark themed version
597 * @cfg {Boolean} toggle is it a slidy toggle button
598 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
599 * @cfg {String} ontext text for on slidy toggle state
600 * @cfg {String} offtext text for off slidy toggle state
601 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
602 * @cfg {Boolean} removeClass remove the standard class..
603 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
606 * Create a new button
607 * @param {Object} config The config object
611 Roo.bootstrap.Button = function(config){
612 Roo.bootstrap.Button.superclass.constructor.call(this, config);
613 this.weightClass = ["btn-default btn-outline-secondary",
625 * When a butotn is pressed
626 * @param {Roo.bootstrap.Button} btn
627 * @param {Roo.EventObject} e
632 * After the button has been toggles
633 * @param {Roo.bootstrap.Button} btn
634 * @param {Roo.EventObject} e
635 * @param {boolean} pressed (also available as button.pressed)
641 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
662 preventDefault: true,
670 getAutoCreate : function(){
678 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
679 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
684 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
686 if (this.toggle == true) {
689 cls: 'slider-frame roo-button',
694 'data-off-text':'OFF',
695 cls: 'slider-button',
701 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
702 cfg.cls += ' '+this.weight;
711 cfg["aria-hidden"] = true;
713 cfg.html = "×";
719 if (this.theme==='default') {
720 cfg.cls = 'btn roo-button';
722 //if (this.parentType != 'Navbar') {
723 this.weight = this.weight.length ? this.weight : 'default';
725 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
727 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
728 var weight = this.weight == 'default' ? 'secondary' : this.weight;
729 cfg.cls += ' btn-' + outline + weight;
730 if (this.weight == 'default') {
732 cfg.cls += ' btn-' + this.weight;
735 } else if (this.theme==='glow') {
738 cfg.cls = 'btn-glow roo-button';
740 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
742 cfg.cls += ' ' + this.weight;
748 this.cls += ' inverse';
752 if (this.active || this.pressed === true) {
753 cfg.cls += ' active';
757 cfg.disabled = 'disabled';
761 Roo.log('changing to ul' );
763 this.glyphicon = 'caret';
764 if (Roo.bootstrap.version == 4) {
765 this.fa = 'caret-down';
770 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
772 //gsRoo.log(this.parentType);
773 if (this.parentType === 'Navbar' && !this.parent().bar) {
774 Roo.log('changing to li?');
783 href : this.href || '#'
786 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
787 cfg.cls += ' dropdown';
794 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
796 if (this.glyphicon) {
797 cfg.html = ' ' + cfg.html;
802 cls: 'glyphicon glyphicon-' + this.glyphicon
807 cfg.html = ' ' + cfg.html;
812 cls: 'fa fas fa-' + this.fa
822 // cfg.cls='btn roo-button';
826 var value = cfg.html;
831 cls: 'glyphicon glyphicon-' + this.glyphicon,
838 cls: 'fa fas fa-' + this.fa,
843 var bw = this.badge_weight.length ? this.badge_weight :
844 (this.weight.length ? this.weight : 'secondary');
845 bw = bw == 'default' ? 'secondary' : bw;
851 cls: 'badge badge-' + bw,
860 cfg.cls += ' dropdown';
861 cfg.html = typeof(cfg.html) != 'undefined' ?
862 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
865 if (cfg.tag !== 'a' && this.href !== '') {
866 throw "Tag must be a to set href.";
867 } else if (this.href.length > 0) {
868 cfg.href = this.href;
871 if(this.removeClass){
876 cfg.target = this.target;
881 initEvents: function() {
882 // Roo.log('init events?');
883 // Roo.log(this.el.dom);
886 if (typeof (this.menu) != 'undefined') {
887 this.menu.parentType = this.xtype;
888 this.menu.triggerEl = this.el;
889 this.addxtype(Roo.apply({}, this.menu));
893 if (this.el.hasClass('roo-button')) {
894 this.el.on('click', this.onClick, this);
896 this.el.select('.roo-button').on('click', this.onClick, this);
899 if(this.removeClass){
900 this.el.on('click', this.onClick, this);
903 this.el.enableDisplayMode();
906 onClick : function(e)
912 Roo.log('button on click ');
913 if(this.preventDefault){
917 if (this.pressed === true || this.pressed === false) {
918 this.toggleActive(e);
922 this.fireEvent('click', this, e);
926 * Enables this button
930 this.disabled = false;
931 this.el.removeClass('disabled');
935 * Disable this button
939 this.disabled = true;
940 this.el.addClass('disabled');
943 * sets the active state on/off,
944 * @param {Boolean} state (optional) Force a particular state
946 setActive : function(v) {
948 this.el[v ? 'addClass' : 'removeClass']('active');
952 * toggles the current active state
954 toggleActive : function(e)
956 this.setActive(!this.pressed);
957 this.fireEvent('toggle', this, e, !this.pressed);
960 * get the current active state
961 * @return {boolean} true if it's active
963 isActive : function()
965 return this.el.hasClass('active');
968 * set the text of the first selected button
970 setText : function(str)
972 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
975 * get the text of the first selected button
979 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
982 setWeight : function(str)
984 this.el.removeClass(this.weightClass);
986 var outline = this.outline ? 'outline-' : '';
987 if (str == 'default') {
988 this.el.addClass('btn-default btn-outline-secondary');
991 this.el.addClass('btn-' + outline + str);
1005 * @class Roo.bootstrap.Column
1006 * @extends Roo.bootstrap.Component
1007 * Bootstrap Column class
1008 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1009 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1010 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1011 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1012 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1013 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1014 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1015 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1018 * @cfg {Boolean} hidden (true|false) hide the element
1019 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1020 * @cfg {String} fa (ban|check|...) font awesome icon
1021 * @cfg {Number} fasize (1|2|....) font awsome size
1023 * @cfg {String} icon (info-sign|check|...) glyphicon name
1025 * @cfg {String} html content of column.
1028 * Create a new Column
1029 * @param {Object} config The config object
1032 Roo.bootstrap.Column = function(config){
1033 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1036 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1054 getAutoCreate : function(){
1055 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1063 ['xs','sm','md','lg'].map(function(size){
1064 //Roo.log( size + ':' + settings[size]);
1066 if (settings[size+'off'] !== false) {
1067 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1070 if (settings[size] === false) {
1074 if (!settings[size]) { // 0 = hidden
1075 cfg.cls += ' hidden-' + size;
1078 cfg.cls += ' col-' + size + '-' + settings[size];
1083 cfg.cls += ' hidden';
1086 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1087 cfg.cls +=' alert alert-' + this.alert;
1091 if (this.html.length) {
1092 cfg.html = this.html;
1096 if (this.fasize > 1) {
1097 fasize = ' fa-' + this.fasize + 'x';
1099 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1104 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1123 * @class Roo.bootstrap.Container
1124 * @extends Roo.bootstrap.Component
1125 * Bootstrap Container class
1126 * @cfg {Boolean} jumbotron is it a jumbotron element
1127 * @cfg {String} html content of element
1128 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1129 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1130 * @cfg {String} header content of header (for panel)
1131 * @cfg {String} footer content of footer (for panel)
1132 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1133 * @cfg {String} tag (header|aside|section) type of HTML tag.
1134 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1135 * @cfg {String} fa font awesome icon
1136 * @cfg {String} icon (info-sign|check|...) glyphicon name
1137 * @cfg {Boolean} hidden (true|false) hide the element
1138 * @cfg {Boolean} expandable (true|false) default false
1139 * @cfg {Boolean} expanded (true|false) default true
1140 * @cfg {String} rheader contet on the right of header
1141 * @cfg {Boolean} clickable (true|false) default false
1145 * Create a new Container
1146 * @param {Object} config The config object
1149 Roo.bootstrap.Container = function(config){
1150 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1156 * After the panel has been expand
1158 * @param {Roo.bootstrap.Container} this
1163 * After the panel has been collapsed
1165 * @param {Roo.bootstrap.Container} this
1170 * When a element is chick
1171 * @param {Roo.bootstrap.Container} this
1172 * @param {Roo.EventObject} e
1178 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1196 getChildContainer : function() {
1202 if (this.panel.length) {
1203 return this.el.select('.panel-body',true).first();
1210 getAutoCreate : function(){
1213 tag : this.tag || 'div',
1217 if (this.jumbotron) {
1218 cfg.cls = 'jumbotron';
1223 // - this is applied by the parent..
1225 // cfg.cls = this.cls + '';
1228 if (this.sticky.length) {
1230 var bd = Roo.get(document.body);
1231 if (!bd.hasClass('bootstrap-sticky')) {
1232 bd.addClass('bootstrap-sticky');
1233 Roo.select('html',true).setStyle('height', '100%');
1236 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1240 if (this.well.length) {
1241 switch (this.well) {
1244 cfg.cls +=' well well-' +this.well;
1253 cfg.cls += ' hidden';
1257 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1258 cfg.cls +=' alert alert-' + this.alert;
1263 if (this.panel.length) {
1264 cfg.cls += ' panel panel-' + this.panel;
1266 if (this.header.length) {
1270 if(this.expandable){
1272 cfg.cls = cfg.cls + ' expandable';
1276 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1284 cls : 'panel-title',
1285 html : (this.expandable ? ' ' : '') + this.header
1289 cls: 'panel-header-right',
1295 cls : 'panel-heading',
1296 style : this.expandable ? 'cursor: pointer' : '',
1304 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1309 if (this.footer.length) {
1311 cls : 'panel-footer',
1320 body.html = this.html || cfg.html;
1321 // prefix with the icons..
1323 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1326 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1331 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1332 cfg.cls = 'container';
1338 initEvents: function()
1340 if(this.expandable){
1341 var headerEl = this.headerEl();
1344 headerEl.on('click', this.onToggleClick, this);
1349 this.el.on('click', this.onClick, this);
1354 onToggleClick : function()
1356 var headerEl = this.headerEl();
1372 if(this.fireEvent('expand', this)) {
1374 this.expanded = true;
1376 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1378 this.el.select('.panel-body',true).first().removeClass('hide');
1380 var toggleEl = this.toggleEl();
1386 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1391 collapse : function()
1393 if(this.fireEvent('collapse', this)) {
1395 this.expanded = false;
1397 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1398 this.el.select('.panel-body',true).first().addClass('hide');
1400 var toggleEl = this.toggleEl();
1406 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1410 toggleEl : function()
1412 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1416 return this.el.select('.panel-heading .fa',true).first();
1419 headerEl : function()
1421 if(!this.el || !this.panel.length || !this.header.length){
1425 return this.el.select('.panel-heading',true).first()
1430 if(!this.el || !this.panel.length){
1434 return this.el.select('.panel-body',true).first()
1437 titleEl : function()
1439 if(!this.el || !this.panel.length || !this.header.length){
1443 return this.el.select('.panel-title',true).first();
1446 setTitle : function(v)
1448 var titleEl = this.titleEl();
1454 titleEl.dom.innerHTML = v;
1457 getTitle : function()
1460 var titleEl = this.titleEl();
1466 return titleEl.dom.innerHTML;
1469 setRightTitle : function(v)
1471 var t = this.el.select('.panel-header-right',true).first();
1477 t.dom.innerHTML = v;
1480 onClick : function(e)
1484 this.fireEvent('click', this, e);
1497 * @class Roo.bootstrap.Img
1498 * @extends Roo.bootstrap.Component
1499 * Bootstrap Img class
1500 * @cfg {Boolean} imgResponsive false | true
1501 * @cfg {String} border rounded | circle | thumbnail
1502 * @cfg {String} src image source
1503 * @cfg {String} alt image alternative text
1504 * @cfg {String} href a tag href
1505 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1506 * @cfg {String} xsUrl xs image source
1507 * @cfg {String} smUrl sm image source
1508 * @cfg {String} mdUrl md image source
1509 * @cfg {String} lgUrl lg image source
1512 * Create a new Input
1513 * @param {Object} config The config object
1516 Roo.bootstrap.Img = function(config){
1517 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1523 * The img click event for the img.
1524 * @param {Roo.EventObject} e
1530 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1532 imgResponsive: true,
1542 getAutoCreate : function()
1544 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1545 return this.createSingleImg();
1550 cls: 'roo-image-responsive-group',
1555 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1557 if(!_this[size + 'Url']){
1563 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1564 html: _this.html || cfg.html,
1565 src: _this[size + 'Url']
1568 img.cls += ' roo-image-responsive-' + size;
1570 var s = ['xs', 'sm', 'md', 'lg'];
1572 s.splice(s.indexOf(size), 1);
1574 Roo.each(s, function(ss){
1575 img.cls += ' hidden-' + ss;
1578 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1579 cfg.cls += ' img-' + _this.border;
1583 cfg.alt = _this.alt;
1596 a.target = _this.target;
1600 cfg.cn.push((_this.href) ? a : img);
1607 createSingleImg : function()
1611 cls: (this.imgResponsive) ? 'img-responsive' : '',
1613 src : 'about:blank' // just incase src get's set to undefined?!?
1616 cfg.html = this.html || cfg.html;
1618 cfg.src = this.src || cfg.src;
1620 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1621 cfg.cls += ' img-' + this.border;
1638 a.target = this.target;
1643 return (this.href) ? a : cfg;
1646 initEvents: function()
1649 this.el.on('click', this.onClick, this);
1654 onClick : function(e)
1656 Roo.log('img onclick');
1657 this.fireEvent('click', this, e);
1660 * Sets the url of the image - used to update it
1661 * @param {String} url the url of the image
1664 setSrc : function(url)
1668 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1669 this.el.dom.src = url;
1673 this.el.select('img', true).first().dom.src = url;
1689 * @class Roo.bootstrap.Link
1690 * @extends Roo.bootstrap.Component
1691 * Bootstrap Link Class
1692 * @cfg {String} alt image alternative text
1693 * @cfg {String} href a tag href
1694 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1695 * @cfg {String} html the content of the link.
1696 * @cfg {String} anchor name for the anchor link
1697 * @cfg {String} fa - favicon
1699 * @cfg {Boolean} preventDefault (true | false) default false
1703 * Create a new Input
1704 * @param {Object} config The config object
1707 Roo.bootstrap.Link = function(config){
1708 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1714 * The img click event for the img.
1715 * @param {Roo.EventObject} e
1721 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1725 preventDefault: false,
1731 getAutoCreate : function()
1733 var html = this.html || '';
1735 if (this.fa !== false) {
1736 html = '<i class="fa fa-' + this.fa + '"></i>';
1741 // anchor's do not require html/href...
1742 if (this.anchor === false) {
1744 cfg.href = this.href || '#';
1746 cfg.name = this.anchor;
1747 if (this.html !== false || this.fa !== false) {
1750 if (this.href !== false) {
1751 cfg.href = this.href;
1755 if(this.alt !== false){
1760 if(this.target !== false) {
1761 cfg.target = this.target;
1767 initEvents: function() {
1769 if(!this.href || this.preventDefault){
1770 this.el.on('click', this.onClick, this);
1774 onClick : function(e)
1776 if(this.preventDefault){
1779 //Roo.log('img onclick');
1780 this.fireEvent('click', this, e);
1793 * @class Roo.bootstrap.Header
1794 * @extends Roo.bootstrap.Component
1795 * Bootstrap Header class
1796 * @cfg {String} html content of header
1797 * @cfg {Number} level (1|2|3|4|5|6) default 1
1800 * Create a new Header
1801 * @param {Object} config The config object
1805 Roo.bootstrap.Header = function(config){
1806 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1809 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1817 getAutoCreate : function(){
1822 tag: 'h' + (1 *this.level),
1823 html: this.html || ''
1835 * Ext JS Library 1.1.1
1836 * Copyright(c) 2006-2007, Ext JS, LLC.
1838 * Originally Released Under LGPL - original licence link has changed is not relivant.
1841 * <script type="text/javascript">
1845 * @class Roo.bootstrap.MenuMgr
1846 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1849 Roo.bootstrap.MenuMgr = function(){
1850 var menus, active, groups = {}, attached = false, lastShow = new Date();
1852 // private - called when first menu is created
1855 active = new Roo.util.MixedCollection();
1856 Roo.get(document).addKeyListener(27, function(){
1857 if(active.length > 0){
1865 if(active && active.length > 0){
1866 var c = active.clone();
1876 if(active.length < 1){
1877 Roo.get(document).un("mouseup", onMouseDown);
1885 var last = active.last();
1886 lastShow = new Date();
1889 Roo.get(document).on("mouseup", onMouseDown);
1894 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1895 m.parentMenu.activeChild = m;
1896 }else if(last && last.isVisible()){
1897 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1902 function onBeforeHide(m){
1904 m.activeChild.hide();
1906 if(m.autoHideTimer){
1907 clearTimeout(m.autoHideTimer);
1908 delete m.autoHideTimer;
1913 function onBeforeShow(m){
1914 var pm = m.parentMenu;
1915 if(!pm && !m.allowOtherMenus){
1917 }else if(pm && pm.activeChild && active != m){
1918 pm.activeChild.hide();
1922 // private this should really trigger on mouseup..
1923 function onMouseDown(e){
1924 Roo.log("on Mouse Up");
1926 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1927 Roo.log("MenuManager hideAll");
1936 function onBeforeCheck(mi, state){
1938 var g = groups[mi.group];
1939 for(var i = 0, l = g.length; i < l; i++){
1941 g[i].setChecked(false);
1950 * Hides all menus that are currently visible
1952 hideAll : function(){
1957 register : function(menu){
1961 menus[menu.id] = menu;
1962 menu.on("beforehide", onBeforeHide);
1963 menu.on("hide", onHide);
1964 menu.on("beforeshow", onBeforeShow);
1965 menu.on("show", onShow);
1967 if(g && menu.events["checkchange"]){
1971 groups[g].push(menu);
1972 menu.on("checkchange", onCheck);
1977 * Returns a {@link Roo.menu.Menu} object
1978 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1979 * be used to generate and return a new Menu instance.
1981 get : function(menu){
1982 if(typeof menu == "string"){ // menu id
1984 }else if(menu.events){ // menu instance
1987 /*else if(typeof menu.length == 'number'){ // array of menu items?
1988 return new Roo.bootstrap.Menu({items:menu});
1989 }else{ // otherwise, must be a config
1990 return new Roo.bootstrap.Menu(menu);
1997 unregister : function(menu){
1998 delete menus[menu.id];
1999 menu.un("beforehide", onBeforeHide);
2000 menu.un("hide", onHide);
2001 menu.un("beforeshow", onBeforeShow);
2002 menu.un("show", onShow);
2004 if(g && menu.events["checkchange"]){
2005 groups[g].remove(menu);
2006 menu.un("checkchange", onCheck);
2011 registerCheckable : function(menuItem){
2012 var g = menuItem.group;
2017 groups[g].push(menuItem);
2018 menuItem.on("beforecheckchange", onBeforeCheck);
2023 unregisterCheckable : function(menuItem){
2024 var g = menuItem.group;
2026 groups[g].remove(menuItem);
2027 menuItem.un("beforecheckchange", onBeforeCheck);
2039 * @class Roo.bootstrap.Menu
2040 * @extends Roo.bootstrap.Component
2041 * Bootstrap Menu class - container for MenuItems
2042 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2043 * @cfg {bool} hidden if the menu should be hidden when rendered.
2044 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2045 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2049 * @param {Object} config The config object
2053 Roo.bootstrap.Menu = function(config){
2054 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2055 if (this.registerMenu && this.type != 'treeview') {
2056 Roo.bootstrap.MenuMgr.register(this);
2063 * Fires before this menu is displayed
2064 * @param {Roo.menu.Menu} this
2069 * Fires before this menu is hidden
2070 * @param {Roo.menu.Menu} this
2075 * Fires after this menu is displayed
2076 * @param {Roo.menu.Menu} this
2081 * Fires after this menu is hidden
2082 * @param {Roo.menu.Menu} this
2087 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2088 * @param {Roo.menu.Menu} this
2089 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2090 * @param {Roo.EventObject} e
2095 * Fires when the mouse is hovering over this menu
2096 * @param {Roo.menu.Menu} this
2097 * @param {Roo.EventObject} e
2098 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2103 * Fires when the mouse exits this menu
2104 * @param {Roo.menu.Menu} this
2105 * @param {Roo.EventObject} e
2106 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2111 * Fires when a menu item contained in this menu is clicked
2112 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2113 * @param {Roo.EventObject} e
2117 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2120 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2124 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2127 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2129 registerMenu : true,
2131 menuItems :false, // stores the menu items..
2141 getChildContainer : function() {
2145 getAutoCreate : function(){
2147 //if (['right'].indexOf(this.align)!==-1) {
2148 // cfg.cn[1].cls += ' pull-right'
2154 cls : 'dropdown-menu' ,
2155 style : 'z-index:1000'
2159 if (this.type === 'submenu') {
2160 cfg.cls = 'submenu active';
2162 if (this.type === 'treeview') {
2163 cfg.cls = 'treeview-menu';
2168 initEvents : function() {
2170 // Roo.log("ADD event");
2171 // Roo.log(this.triggerEl.dom);
2173 this.triggerEl.on('click', this.onTriggerClick, this);
2175 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2178 if (this.triggerEl.hasClass('nav-item')) {
2179 // dropdown toggle on the 'a' in BS4?
2180 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2182 this.triggerEl.addClass('dropdown-toggle');
2185 this.el.on('touchstart' , this.onTouch, this);
2187 this.el.on('click' , this.onClick, this);
2189 this.el.on("mouseover", this.onMouseOver, this);
2190 this.el.on("mouseout", this.onMouseOut, this);
2194 findTargetItem : function(e)
2196 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2200 //Roo.log(t); Roo.log(t.id);
2202 //Roo.log(this.menuitems);
2203 return this.menuitems.get(t.id);
2205 //return this.items.get(t.menuItemId);
2211 onTouch : function(e)
2213 Roo.log("menu.onTouch");
2214 //e.stopEvent(); this make the user popdown broken
2218 onClick : function(e)
2220 Roo.log("menu.onClick");
2222 var t = this.findTargetItem(e);
2223 if(!t || t.isContainer){
2228 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2229 if(t == this.activeItem && t.shouldDeactivate(e)){
2230 this.activeItem.deactivate();
2231 delete this.activeItem;
2235 this.setActiveItem(t, true);
2243 Roo.log('pass click event');
2247 this.fireEvent("click", this, t, e);
2251 if(!t.href.length || t.href == '#'){
2252 (function() { _this.hide(); }).defer(100);
2257 onMouseOver : function(e){
2258 var t = this.findTargetItem(e);
2261 // if(t.canActivate && !t.disabled){
2262 // this.setActiveItem(t, true);
2266 this.fireEvent("mouseover", this, e, t);
2268 isVisible : function(){
2269 return !this.hidden;
2271 onMouseOut : function(e){
2272 var t = this.findTargetItem(e);
2275 // if(t == this.activeItem && t.shouldDeactivate(e)){
2276 // this.activeItem.deactivate();
2277 // delete this.activeItem;
2280 this.fireEvent("mouseout", this, e, t);
2285 * Displays this menu relative to another element
2286 * @param {String/HTMLElement/Roo.Element} element The element to align to
2287 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2288 * the element (defaults to this.defaultAlign)
2289 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2291 show : function(el, pos, parentMenu){
2292 this.parentMenu = parentMenu;
2296 this.fireEvent("beforeshow", this);
2297 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2300 * Displays this menu at a specific xy position
2301 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2302 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2304 showAt : function(xy, parentMenu, /* private: */_e){
2305 this.parentMenu = parentMenu;
2310 this.fireEvent("beforeshow", this);
2311 //xy = this.el.adjustForConstraints(xy);
2315 this.hideMenuItems();
2316 this.hidden = false;
2317 this.triggerEl.addClass('open');
2318 this.el.addClass('show');
2320 // reassign x when hitting right
2321 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2322 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2325 // reassign y when hitting bottom
2326 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2327 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2330 // but the list may align on trigger left or trigger top... should it be a properity?
2332 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2337 this.fireEvent("show", this);
2343 this.doFocus.defer(50, this);
2347 doFocus : function(){
2349 this.focusEl.focus();
2354 * Hides this menu and optionally all parent menus
2355 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2357 hide : function(deep)
2360 this.hideMenuItems();
2361 if(this.el && this.isVisible()){
2362 this.fireEvent("beforehide", this);
2363 if(this.activeItem){
2364 this.activeItem.deactivate();
2365 this.activeItem = null;
2367 this.triggerEl.removeClass('open');;
2368 this.el.removeClass('show');
2370 this.fireEvent("hide", this);
2372 if(deep === true && this.parentMenu){
2373 this.parentMenu.hide(true);
2377 onTriggerClick : function(e)
2379 Roo.log('trigger click');
2381 var target = e.getTarget();
2383 Roo.log(target.nodeName.toLowerCase());
2385 if(target.nodeName.toLowerCase() === 'i'){
2391 onTriggerPress : function(e)
2393 Roo.log('trigger press');
2394 //Roo.log(e.getTarget());
2395 // Roo.log(this.triggerEl.dom);
2397 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2398 var pel = Roo.get(e.getTarget());
2399 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2400 Roo.log('is treeview or dropdown?');
2404 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2408 if (this.isVisible()) {
2413 this.show(this.triggerEl, '?', false);
2416 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2423 hideMenuItems : function()
2425 Roo.log("hide Menu Items");
2429 //$(backdrop).remove()
2430 this.el.select('.open',true).each(function(aa) {
2432 aa.removeClass('open');
2433 //var parent = getParent($(this))
2434 //var relatedTarget = { relatedTarget: this }
2436 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2437 //if (e.isDefaultPrevented()) return
2438 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2441 addxtypeChild : function (tree, cntr) {
2442 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2444 this.menuitems.add(comp);
2456 this.getEl().dom.innerHTML = '';
2457 this.menuitems.clear();
2471 * @class Roo.bootstrap.MenuItem
2472 * @extends Roo.bootstrap.Component
2473 * Bootstrap MenuItem class
2474 * @cfg {String} html the menu label
2475 * @cfg {String} href the link
2476 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2477 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2478 * @cfg {Boolean} active used on sidebars to highlight active itesm
2479 * @cfg {String} fa favicon to show on left of menu item.
2480 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2484 * Create a new MenuItem
2485 * @param {Object} config The config object
2489 Roo.bootstrap.MenuItem = function(config){
2490 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2495 * The raw click event for the entire grid.
2496 * @param {Roo.bootstrap.MenuItem} this
2497 * @param {Roo.EventObject} e
2503 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2507 preventDefault: false,
2508 isContainer : false,
2512 getAutoCreate : function(){
2514 if(this.isContainer){
2517 cls: 'dropdown-menu-item '
2527 cls : 'dropdown-item',
2532 if (this.fa !== false) {
2535 cls : 'fa fa-' + this.fa
2544 cls: 'dropdown-menu-item',
2547 if (this.parent().type == 'treeview') {
2548 cfg.cls = 'treeview-menu';
2551 cfg.cls += ' active';
2556 anc.href = this.href || cfg.cn[0].href ;
2557 ctag.html = this.html || cfg.cn[0].html ;
2561 initEvents: function()
2563 if (this.parent().type == 'treeview') {
2564 this.el.select('a').on('click', this.onClick, this);
2568 this.menu.parentType = this.xtype;
2569 this.menu.triggerEl = this.el;
2570 this.menu = this.addxtype(Roo.apply({}, this.menu));
2574 onClick : function(e)
2576 Roo.log('item on click ');
2578 if(this.preventDefault){
2581 //this.parent().hideMenuItems();
2583 this.fireEvent('click', this, e);
2602 * @class Roo.bootstrap.MenuSeparator
2603 * @extends Roo.bootstrap.Component
2604 * Bootstrap MenuSeparator class
2607 * Create a new MenuItem
2608 * @param {Object} config The config object
2612 Roo.bootstrap.MenuSeparator = function(config){
2613 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2616 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2618 getAutoCreate : function(){
2637 * @class Roo.bootstrap.Modal
2638 * @extends Roo.bootstrap.Component
2639 * Bootstrap Modal class
2640 * @cfg {String} title Title of dialog
2641 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2642 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2643 * @cfg {Boolean} specificTitle default false
2644 * @cfg {Array} buttons Array of buttons or standard button set..
2645 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2646 * @cfg {Boolean} animate default true
2647 * @cfg {Boolean} allow_close default true
2648 * @cfg {Boolean} fitwindow default false
2649 * @cfg {String} size (sm|lg) default empty
2650 * @cfg {Number} max_width set the max width of modal
2654 * Create a new Modal Dialog
2655 * @param {Object} config The config object
2658 Roo.bootstrap.Modal = function(config){
2659 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2664 * The raw btnclick event for the button
2665 * @param {Roo.EventObject} e
2670 * Fire when dialog resize
2671 * @param {Roo.bootstrap.Modal} this
2672 * @param {Roo.EventObject} e
2676 this.buttons = this.buttons || [];
2679 this.tmpl = Roo.factory(this.tmpl);
2684 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2686 title : 'test dialog',
2696 specificTitle: false,
2698 buttonPosition: 'right',
2721 onRender : function(ct, position)
2723 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2726 var cfg = Roo.apply({}, this.getAutoCreate());
2729 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2731 //if (!cfg.name.length) {
2735 cfg.cls += ' ' + this.cls;
2738 cfg.style = this.style;
2740 this.el = Roo.get(document.body).createChild(cfg, position);
2742 //var type = this.el.dom.type;
2745 if(this.tabIndex !== undefined){
2746 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2749 this.dialogEl = this.el.select('.modal-dialog',true).first();
2750 this.bodyEl = this.el.select('.modal-body',true).first();
2751 this.closeEl = this.el.select('.modal-header .close', true).first();
2752 this.headerEl = this.el.select('.modal-header',true).first();
2753 this.titleEl = this.el.select('.modal-title',true).first();
2754 this.footerEl = this.el.select('.modal-footer',true).first();
2756 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2758 //this.el.addClass("x-dlg-modal");
2760 if (this.buttons.length) {
2761 Roo.each(this.buttons, function(bb) {
2762 var b = Roo.apply({}, bb);
2763 b.xns = b.xns || Roo.bootstrap;
2764 b.xtype = b.xtype || 'Button';
2765 if (typeof(b.listeners) == 'undefined') {
2766 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2769 var btn = Roo.factory(b);
2771 btn.render(this.getButtonContainer());
2775 // render the children.
2778 if(typeof(this.items) != 'undefined'){
2779 var items = this.items;
2782 for(var i =0;i < items.length;i++) {
2783 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2787 this.items = nitems;
2789 // where are these used - they used to be body/close/footer
2793 //this.el.addClass([this.fieldClass, this.cls]);
2797 getAutoCreate : function()
2801 html : this.html || ''
2806 cls : 'modal-title',
2810 if(this.specificTitle){
2816 if (this.allow_close && Roo.bootstrap.version == 3) {
2826 if (this.allow_close && Roo.bootstrap.version == 4) {
2836 if(this.size.length){
2837 size = 'modal-' + this.size;
2840 var footer = Roo.bootstrap.version == 3 ?
2842 cls : 'modal-footer',
2846 cls: 'btn-' + this.buttonPosition
2851 { // BS4 uses mr-auto on left buttons....
2852 cls : 'modal-footer'
2863 cls: "modal-dialog " + size,
2866 cls : "modal-content",
2869 cls : 'modal-header',
2884 modal.cls += ' fade';
2890 getChildContainer : function() {
2895 getButtonContainer : function() {
2897 return Roo.bootstrap.version == 4 ?
2898 this.el.select('.modal-footer',true).first()
2899 : this.el.select('.modal-footer div',true).first();
2902 initEvents : function()
2904 if (this.allow_close) {
2905 this.closeEl.on('click', this.hide, this);
2907 Roo.EventManager.onWindowResize(this.resize, this, true);
2914 this.maskEl.setSize(
2915 Roo.lib.Dom.getViewWidth(true),
2916 Roo.lib.Dom.getViewHeight(true)
2919 if (this.fitwindow) {
2921 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2922 this.height || Roo.lib.Dom.getViewportHeight(true) - 60
2927 if(this.max_width !== 0) {
2929 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2932 this.setSize(w, this.height);
2936 if(this.max_height) {
2937 this.setSize(w,Math.min(
2939 Roo.lib.Dom.getViewportHeight(true) - 60
2945 if(!this.fit_content) {
2946 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2950 this.setSize(w, Math.min(
2952 this.headerEl.getHeight() +
2953 this.footerEl.getHeight() +
2954 this.getChildHeight(this.bodyEl.dom.childNodes),
2955 Roo.lib.Dom.getViewportHeight(true) - 60)
2961 setSize : function(w,h)
2972 if (!this.rendered) {
2976 //this.el.setStyle('display', 'block');
2977 this.el.removeClass('hideing');
2978 this.el.dom.style.display='block';
2980 Roo.get(document.body).addClass('modal-open');
2982 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2985 this.el.addClass('show');
2986 this.el.addClass('in');
2989 this.el.addClass('show');
2990 this.el.addClass('in');
2993 // not sure how we can show data in here..
2995 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2998 Roo.get(document.body).addClass("x-body-masked");
3000 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3001 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3002 this.maskEl.dom.style.display = 'block';
3003 this.maskEl.addClass('show');
3008 this.fireEvent('show', this);
3010 // set zindex here - otherwise it appears to be ignored...
3011 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3014 this.items.forEach( function(e) {
3015 e.layout ? e.layout() : false;
3023 if(this.fireEvent("beforehide", this) !== false){
3025 this.maskEl.removeClass('show');
3027 this.maskEl.dom.style.display = '';
3028 Roo.get(document.body).removeClass("x-body-masked");
3029 this.el.removeClass('in');
3030 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3032 if(this.animate){ // why
3033 this.el.addClass('hideing');
3034 this.el.removeClass('show');
3036 if (!this.el.hasClass('hideing')) {
3037 return; // it's been shown again...
3040 this.el.dom.style.display='';
3042 Roo.get(document.body).removeClass('modal-open');
3043 this.el.removeClass('hideing');
3047 this.el.removeClass('show');
3048 this.el.dom.style.display='';
3049 Roo.get(document.body).removeClass('modal-open');
3052 this.fireEvent('hide', this);
3055 isVisible : function()
3058 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3062 addButton : function(str, cb)
3066 var b = Roo.apply({}, { html : str } );
3067 b.xns = b.xns || Roo.bootstrap;
3068 b.xtype = b.xtype || 'Button';
3069 if (typeof(b.listeners) == 'undefined') {
3070 b.listeners = { click : cb.createDelegate(this) };
3073 var btn = Roo.factory(b);
3075 btn.render(this.getButtonContainer());
3081 setDefaultButton : function(btn)
3083 //this.el.select('.modal-footer').()
3087 resizeTo: function(w,h)
3091 this.dialogEl.setWidth(w);
3092 if (this.diff === false) {
3093 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
3096 this.bodyEl.setHeight(h - this.diff);
3098 this.fireEvent('resize', this);
3101 setContentSize : function(w, h)
3105 onButtonClick: function(btn,e)
3108 this.fireEvent('btnclick', btn.name, e);
3111 * Set the title of the Dialog
3112 * @param {String} str new Title
3114 setTitle: function(str) {
3115 this.titleEl.dom.innerHTML = str;
3118 * Set the body of the Dialog
3119 * @param {String} str new Title
3121 setBody: function(str) {
3122 this.bodyEl.dom.innerHTML = str;
3125 * Set the body of the Dialog using the template
3126 * @param {Obj} data - apply this data to the template and replace the body contents.
3128 applyBody: function(obj)
3131 Roo.log("Error - using apply Body without a template");
3134 this.tmpl.overwrite(this.bodyEl, obj);
3137 getChildHeight : function(child_nodes)
3141 child_nodes.length == 0
3146 var child_height = 0;
3148 for(var i = 0; i < child_nodes.length; i++) {
3151 * for modal with tabs...
3152 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3154 var layout_childs = child_nodes[i].childNodes;
3156 for(var j = 0; j < layout_childs.length; j++) {
3158 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3160 var layout_body_childs = layout_childs[j].childNodes;
3162 for(var k = 0; k < layout_body_childs.length; k++) {
3164 if(layout_body_childs[k].classList.contains('navbar')) {
3165 child_height += layout_body_childs[k].offsetHeight;
3169 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3171 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3173 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3175 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3176 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3191 child_height += child_nodes[i].offsetHeight;
3192 // Roo.log(child_nodes[i].offsetHeight);
3195 return child_height;
3201 Roo.apply(Roo.bootstrap.Modal, {
3203 * Button config that displays a single OK button
3212 * Button config that displays Yes and No buttons
3228 * Button config that displays OK and Cancel buttons
3243 * Button config that displays Yes, No and Cancel buttons
3267 * messagebox - can be used as a replace
3271 * @class Roo.MessageBox
3272 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3276 Roo.Msg.alert('Status', 'Changes saved successfully.');
3278 // Prompt for user data:
3279 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3281 // process text value...
3285 // Show a dialog using config options:
3287 title:'Save Changes?',
3288 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3289 buttons: Roo.Msg.YESNOCANCEL,
3296 Roo.bootstrap.MessageBox = function(){
3297 var dlg, opt, mask, waitTimer;
3298 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3299 var buttons, activeTextEl, bwidth;
3303 var handleButton = function(button){
3305 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3309 var handleHide = function(){
3311 dlg.el.removeClass(opt.cls);
3314 // Roo.TaskMgr.stop(waitTimer);
3315 // waitTimer = null;
3320 var updateButtons = function(b){
3323 buttons["ok"].hide();
3324 buttons["cancel"].hide();
3325 buttons["yes"].hide();
3326 buttons["no"].hide();
3327 dlg.footerEl.hide();
3331 dlg.footerEl.show();
3332 for(var k in buttons){
3333 if(typeof buttons[k] != "function"){
3336 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3337 width += buttons[k].el.getWidth()+15;
3347 var handleEsc = function(d, k, e){
3348 if(opt && opt.closable !== false){
3358 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3359 * @return {Roo.BasicDialog} The BasicDialog element
3361 getDialog : function(){
3363 dlg = new Roo.bootstrap.Modal( {
3366 //constraintoviewport:false,
3368 //collapsible : false,
3373 //buttonAlign:"center",
3374 closeClick : function(){
3375 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3378 handleButton("cancel");
3383 dlg.on("hide", handleHide);
3385 //dlg.addKeyListener(27, handleEsc);
3387 this.buttons = buttons;
3388 var bt = this.buttonText;
3389 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3390 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3391 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3392 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3394 bodyEl = dlg.bodyEl.createChild({
3396 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3397 '<textarea class="roo-mb-textarea"></textarea>' +
3398 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3400 msgEl = bodyEl.dom.firstChild;
3401 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3402 textboxEl.enableDisplayMode();
3403 textboxEl.addKeyListener([10,13], function(){
3404 if(dlg.isVisible() && opt && opt.buttons){
3407 }else if(opt.buttons.yes){
3408 handleButton("yes");
3412 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3413 textareaEl.enableDisplayMode();
3414 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3415 progressEl.enableDisplayMode();
3417 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3418 var pf = progressEl.dom.firstChild;
3420 pp = Roo.get(pf.firstChild);
3421 pp.setHeight(pf.offsetHeight);
3429 * Updates the message box body text
3430 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3431 * the XHTML-compliant non-breaking space character '&#160;')
3432 * @return {Roo.MessageBox} This message box
3434 updateText : function(text)
3436 if(!dlg.isVisible() && !opt.width){
3437 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3438 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3440 msgEl.innerHTML = text || ' ';
3442 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3443 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3445 Math.min(opt.width || cw , this.maxWidth),
3446 Math.max(opt.minWidth || this.minWidth, bwidth)
3449 activeTextEl.setWidth(w);
3451 if(dlg.isVisible()){
3452 dlg.fixedcenter = false;
3454 // to big, make it scroll. = But as usual stupid IE does not support
3457 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3458 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3459 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3461 bodyEl.dom.style.height = '';
3462 bodyEl.dom.style.overflowY = '';
3465 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3467 bodyEl.dom.style.overflowX = '';
3470 dlg.setContentSize(w, bodyEl.getHeight());
3471 if(dlg.isVisible()){
3472 dlg.fixedcenter = true;
3478 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3479 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3480 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3481 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3482 * @return {Roo.MessageBox} This message box
3484 updateProgress : function(value, text){
3486 this.updateText(text);
3489 if (pp) { // weird bug on my firefox - for some reason this is not defined
3490 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3491 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3497 * Returns true if the message box is currently displayed
3498 * @return {Boolean} True if the message box is visible, else false
3500 isVisible : function(){
3501 return dlg && dlg.isVisible();
3505 * Hides the message box if it is displayed
3508 if(this.isVisible()){
3514 * Displays a new message box, or reinitializes an existing message box, based on the config options
3515 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3516 * The following config object properties are supported:
3518 Property Type Description
3519 ---------- --------------- ------------------------------------------------------------------------------------
3520 animEl String/Element An id or Element from which the message box should animate as it opens and
3521 closes (defaults to undefined)
3522 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3523 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3524 closable Boolean False to hide the top-right close button (defaults to true). Note that
3525 progress and wait dialogs will ignore this property and always hide the
3526 close button as they can only be closed programmatically.
3527 cls String A custom CSS class to apply to the message box element
3528 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3529 displayed (defaults to 75)
3530 fn Function A callback function to execute after closing the dialog. The arguments to the
3531 function will be btn (the name of the button that was clicked, if applicable,
3532 e.g. "ok"), and text (the value of the active text field, if applicable).
3533 Progress and wait dialogs will ignore this option since they do not respond to
3534 user actions and can only be closed programmatically, so any required function
3535 should be called by the same code after it closes the dialog.
3536 icon String A CSS class that provides a background image to be used as an icon for
3537 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3538 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3539 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3540 modal Boolean False to allow user interaction with the page while the message box is
3541 displayed (defaults to true)
3542 msg String A string that will replace the existing message box body text (defaults
3543 to the XHTML-compliant non-breaking space character ' ')
3544 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3545 progress Boolean True to display a progress bar (defaults to false)
3546 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3547 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3548 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3549 title String The title text
3550 value String The string value to set into the active textbox element if displayed
3551 wait Boolean True to display a progress bar (defaults to false)
3552 width Number The width of the dialog in pixels
3559 msg: 'Please enter your address:',
3561 buttons: Roo.MessageBox.OKCANCEL,
3564 animEl: 'addAddressBtn'
3567 * @param {Object} config Configuration options
3568 * @return {Roo.MessageBox} This message box
3570 show : function(options)
3573 // this causes nightmares if you show one dialog after another
3574 // especially on callbacks..
3576 if(this.isVisible()){
3579 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3580 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3581 Roo.log("New Dialog Message:" + options.msg )
3582 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3583 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3586 var d = this.getDialog();
3588 d.setTitle(opt.title || " ");
3589 d.closeEl.setDisplayed(opt.closable !== false);
3590 activeTextEl = textboxEl;
3591 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3596 textareaEl.setHeight(typeof opt.multiline == "number" ?
3597 opt.multiline : this.defaultTextHeight);
3598 activeTextEl = textareaEl;
3607 progressEl.setDisplayed(opt.progress === true);
3608 this.updateProgress(0);
3609 activeTextEl.dom.value = opt.value || "";
3611 dlg.setDefaultButton(activeTextEl);
3613 var bs = opt.buttons;
3617 }else if(bs && bs.yes){
3618 db = buttons["yes"];
3620 dlg.setDefaultButton(db);
3622 bwidth = updateButtons(opt.buttons);
3623 this.updateText(opt.msg);
3625 d.el.addClass(opt.cls);
3627 d.proxyDrag = opt.proxyDrag === true;
3628 d.modal = opt.modal !== false;
3629 d.mask = opt.modal !== false ? mask : false;
3631 // force it to the end of the z-index stack so it gets a cursor in FF
3632 document.body.appendChild(dlg.el.dom);
3633 d.animateTarget = null;
3634 d.show(options.animEl);
3640 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3641 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3642 * and closing the message box when the process is complete.
3643 * @param {String} title The title bar text
3644 * @param {String} msg The message box body text
3645 * @return {Roo.MessageBox} This message box
3647 progress : function(title, msg){
3654 minWidth: this.minProgressWidth,
3661 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3662 * If a callback function is passed it will be called after the user clicks the button, and the
3663 * id of the button that was clicked will be passed as the only parameter to the callback
3664 * (could also be the top-right close button).
3665 * @param {String} title The title bar text
3666 * @param {String} msg The message box body text
3667 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3668 * @param {Object} scope (optional) The scope of the callback function
3669 * @return {Roo.MessageBox} This message box
3671 alert : function(title, msg, fn, scope)
3686 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3687 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3688 * You are responsible for closing the message box when the process is complete.
3689 * @param {String} msg The message box body text
3690 * @param {String} title (optional) The title bar text
3691 * @return {Roo.MessageBox} This message box
3693 wait : function(msg, title){
3704 waitTimer = Roo.TaskMgr.start({
3706 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3714 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3715 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3716 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3717 * @param {String} title The title bar text
3718 * @param {String} msg The message box body text
3719 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3720 * @param {Object} scope (optional) The scope of the callback function
3721 * @return {Roo.MessageBox} This message box
3723 confirm : function(title, msg, fn, scope){
3727 buttons: this.YESNO,
3736 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3737 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3738 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3739 * (could also be the top-right close button) and the text that was entered will be passed as the two
3740 * parameters to the callback.
3741 * @param {String} title The title bar text
3742 * @param {String} msg The message box body text
3743 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3744 * @param {Object} scope (optional) The scope of the callback function
3745 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3746 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3747 * @return {Roo.MessageBox} This message box
3749 prompt : function(title, msg, fn, scope, multiline){
3753 buttons: this.OKCANCEL,
3758 multiline: multiline,
3765 * Button config that displays a single OK button
3770 * Button config that displays Yes and No buttons
3773 YESNO : {yes:true, no:true},
3775 * Button config that displays OK and Cancel buttons
3778 OKCANCEL : {ok:true, cancel:true},
3780 * Button config that displays Yes, No and Cancel buttons
3783 YESNOCANCEL : {yes:true, no:true, cancel:true},
3786 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3789 defaultTextHeight : 75,
3791 * The maximum width in pixels of the message box (defaults to 600)
3796 * The minimum width in pixels of the message box (defaults to 100)
3801 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3802 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3805 minProgressWidth : 250,
3807 * An object containing the default button text strings that can be overriden for localized language support.
3808 * Supported properties are: ok, cancel, yes and no.
3809 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3822 * Shorthand for {@link Roo.MessageBox}
3824 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3825 Roo.Msg = Roo.Msg || Roo.MessageBox;
3834 * @class Roo.bootstrap.Navbar
3835 * @extends Roo.bootstrap.Component
3836 * Bootstrap Navbar class
3839 * Create a new Navbar
3840 * @param {Object} config The config object
3844 Roo.bootstrap.Navbar = function(config){
3845 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3849 * @event beforetoggle
3850 * Fire before toggle the menu
3851 * @param {Roo.EventObject} e
3853 "beforetoggle" : true
3857 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3866 getAutoCreate : function(){
3869 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3873 initEvents :function ()
3875 //Roo.log(this.el.select('.navbar-toggle',true));
3876 this.el.select('.navbar-toggle',true).on('click', function() {
3877 if(this.fireEvent('beforetoggle', this) !== false){
3878 var ce = this.el.select('.navbar-collapse',true).first();
3879 ce.toggleClass('in'); // old...
3880 if (ce.hasClass('collapse')) {
3882 ce.removeClass('collapse');
3883 ce.addClass('show');
3884 var h = ce.getHeight();
3886 ce.removeClass('show');
3887 // at this point we should be able to see it..
3888 ce.addClass('collapsing');
3890 ce.setHeight(0); // resize it ...
3891 ce.on('transitionend', function() {
3892 Roo.log('done transition');
3893 ce.removeClass('collapsing');
3894 ce.addClass('show');
3895 ce.removeClass('collapse');
3897 ce.dom.style.height = '';
3898 }, this, { single: true} );
3902 ce.setHeight(ce.getHeight());
3903 ce.removeClass('show');
3904 ce.addClass('collapsing');
3906 ce.on('transitionend', function() {
3907 ce.dom.style.height = '';
3908 ce.removeClass('collapsing');
3909 ce.addClass('collapse');
3910 }, this, { single: true} );
3922 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3924 var size = this.el.getSize();
3925 this.maskEl.setSize(size.width, size.height);
3926 this.maskEl.enableDisplayMode("block");
3935 getChildContainer : function()
3937 if (this.el.select('.collapse').getCount()) {
3938 return this.el.select('.collapse',true).first();
3971 * @class Roo.bootstrap.NavSimplebar
3972 * @extends Roo.bootstrap.Navbar
3973 * Bootstrap Sidebar class
3975 * @cfg {Boolean} inverse is inverted color
3977 * @cfg {String} type (nav | pills | tabs)
3978 * @cfg {Boolean} arrangement stacked | justified
3979 * @cfg {String} align (left | right) alignment
3981 * @cfg {Boolean} main (true|false) main nav bar? default false
3982 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3984 * @cfg {String} tag (header|footer|nav|div) default is nav
3986 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
3990 * Create a new Sidebar
3991 * @param {Object} config The config object
3995 Roo.bootstrap.NavSimplebar = function(config){
3996 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3999 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4015 getAutoCreate : function(){
4019 tag : this.tag || 'div',
4020 cls : 'navbar navbar-expand-lg'
4022 if (['light','white'].indexOf(this.weight) > -1) {
4023 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4025 cfg.cls += ' bg-' + this.weight;
4028 cfg.cls += ' navbar-inverse';
4032 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4034 if (Roo.bootstrap.version == 4) {
4046 this.type = this.type || 'nav';
4047 if (['tabs','pills'].indexOf(this.type)!==-1) {
4048 cfg.cn[0].cls += ' nav-' + this.type
4052 if (this.type!=='nav') {
4053 Roo.log('nav type must be nav/tabs/pills')
4055 cfg.cn[0].cls += ' navbar-nav'
4061 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
4062 cfg.cn[0].cls += ' nav-' + this.arrangement;
4066 if (this.align === 'right') {
4067 cfg.cn[0].cls += ' navbar-right';
4092 * navbar-expand-md fixed-top
4096 * @class Roo.bootstrap.NavHeaderbar
4097 * @extends Roo.bootstrap.NavSimplebar
4098 * Bootstrap Sidebar class
4100 * @cfg {String} brand what is brand
4101 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4102 * @cfg {String} brand_href href of the brand
4103 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4104 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4105 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4106 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4109 * Create a new Sidebar
4110 * @param {Object} config The config object
4114 Roo.bootstrap.NavHeaderbar = function(config){
4115 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4119 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4126 desktopCenter : false,
4129 getAutoCreate : function(){
4132 tag: this.nav || 'nav',
4133 cls: 'navbar navbar-expand-md',
4139 if (this.desktopCenter) {
4140 cn.push({cls : 'container', cn : []});
4148 cls: 'navbar-toggle navbar-toggler',
4149 'data-toggle': 'collapse',
4154 html: 'Toggle navigation'
4158 cls: 'icon-bar navbar-toggler-icon'
4171 cn.push( Roo.bootstrap.version == 4 ? btn : {
4173 cls: 'navbar-header',
4182 cls: 'collapse navbar-collapse',
4186 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4188 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4189 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4191 // tag can override this..
4193 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4196 if (this.brand !== '') {
4197 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4198 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4200 href: this.brand_href ? this.brand_href : '#',
4201 cls: 'navbar-brand',
4209 cfg.cls += ' main-nav';
4217 getHeaderChildContainer : function()
4219 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4220 return this.el.select('.navbar-header',true).first();
4223 return this.getChildContainer();
4227 initEvents : function()
4229 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4231 if (this.autohide) {
4236 Roo.get(document).on('scroll',function(e) {
4237 var ns = Roo.get(document).getScroll().top;
4238 var os = prevScroll;
4242 ft.removeClass('slideDown');
4243 ft.addClass('slideUp');
4246 ft.removeClass('slideUp');
4247 ft.addClass('slideDown');
4268 * @class Roo.bootstrap.NavSidebar
4269 * @extends Roo.bootstrap.Navbar
4270 * Bootstrap Sidebar class
4273 * Create a new Sidebar
4274 * @param {Object} config The config object
4278 Roo.bootstrap.NavSidebar = function(config){
4279 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4282 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4284 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4286 getAutoCreate : function(){
4291 cls: 'sidebar sidebar-nav'
4313 * @class Roo.bootstrap.NavGroup
4314 * @extends Roo.bootstrap.Component
4315 * Bootstrap NavGroup class
4316 * @cfg {String} align (left|right)
4317 * @cfg {Boolean} inverse
4318 * @cfg {String} type (nav|pills|tab) default nav
4319 * @cfg {String} navId - reference Id for navbar.
4323 * Create a new nav group
4324 * @param {Object} config The config object
4327 Roo.bootstrap.NavGroup = function(config){
4328 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4331 Roo.bootstrap.NavGroup.register(this);
4335 * Fires when the active item changes
4336 * @param {Roo.bootstrap.NavGroup} this
4337 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4338 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4345 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4356 getAutoCreate : function()
4358 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4364 if (Roo.bootstrap.version == 4) {
4365 if (this.type == 'pills') {
4366 cfg.cls = ' nav-pills';
4369 if (['tabs','pills'].indexOf(this.type)!==-1) {
4370 cfg.cls += ' nav-' + this.type
4372 if (this.type !== 'nav') {
4373 Roo.log('nav type must be nav/tabs/pills')
4375 cfg.cls += ' navbar-nav'
4379 if (this.parent() && this.parent().sidebar) {
4382 cls: 'dashboard-menu sidebar-menu'
4388 if (this.form === true) {
4391 cls: 'navbar-form form-inline'
4394 if (this.align === 'right') {
4395 cfg.cls += ' navbar-right ml-md-auto';
4397 cfg.cls += ' navbar-left';
4401 if (this.align === 'right') {
4402 cfg.cls += ' navbar-right ml-md-auto';
4404 cfg.cls += ' mr-auto';
4408 cfg.cls += ' navbar-inverse';
4416 * sets the active Navigation item
4417 * @param {Roo.bootstrap.NavItem} the new current navitem
4419 setActiveItem : function(item)
4422 Roo.each(this.navItems, function(v){
4427 v.setActive(false, true);
4434 item.setActive(true, true);
4435 this.fireEvent('changed', this, item, prev);
4440 * gets the active Navigation item
4441 * @return {Roo.bootstrap.NavItem} the current navitem
4443 getActive : function()
4447 Roo.each(this.navItems, function(v){
4458 indexOfNav : function()
4462 Roo.each(this.navItems, function(v,i){
4473 * adds a Navigation item
4474 * @param {Roo.bootstrap.NavItem} the navitem to add
4476 addItem : function(cfg)
4478 if (this.form && Roo.bootstrap.version == 4) {
4481 var cn = new Roo.bootstrap.NavItem(cfg);
4483 cn.parentId = this.id;
4484 cn.onRender(this.el, null);
4488 * register a Navigation item
4489 * @param {Roo.bootstrap.NavItem} the navitem to add
4491 register : function(item)
4493 this.navItems.push( item);
4494 item.navId = this.navId;
4499 * clear all the Navigation item
4502 clearAll : function()
4505 this.el.dom.innerHTML = '';
4508 getNavItem: function(tabId)
4511 Roo.each(this.navItems, function(e) {
4512 if (e.tabId == tabId) {
4522 setActiveNext : function()
4524 var i = this.indexOfNav(this.getActive());
4525 if (i > this.navItems.length) {
4528 this.setActiveItem(this.navItems[i+1]);
4530 setActivePrev : function()
4532 var i = this.indexOfNav(this.getActive());
4536 this.setActiveItem(this.navItems[i-1]);
4538 clearWasActive : function(except) {
4539 Roo.each(this.navItems, function(e) {
4540 if (e.tabId != except.tabId && e.was_active) {
4541 e.was_active = false;
4548 getWasActive : function ()
4551 Roo.each(this.navItems, function(e) {
4566 Roo.apply(Roo.bootstrap.NavGroup, {
4570 * register a Navigation Group
4571 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4573 register : function(navgrp)
4575 this.groups[navgrp.navId] = navgrp;
4579 * fetch a Navigation Group based on the navigation ID
4580 * @param {string} the navgroup to add
4581 * @returns {Roo.bootstrap.NavGroup} the navgroup
4583 get: function(navId) {
4584 if (typeof(this.groups[navId]) == 'undefined') {
4586 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4588 return this.groups[navId] ;
4603 * @class Roo.bootstrap.NavItem
4604 * @extends Roo.bootstrap.Component
4605 * Bootstrap Navbar.NavItem class
4606 * @cfg {String} href link to
4607 * @cfg {String} html content of button
4608 * @cfg {String} badge text inside badge
4609 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4610 * @cfg {String} glyphicon DEPRICATED - use fa
4611 * @cfg {String} icon DEPRICATED - use fa
4612 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4613 * @cfg {Boolean} active Is item active
4614 * @cfg {Boolean} disabled Is item disabled
4616 * @cfg {Boolean} preventDefault (true | false) default false
4617 * @cfg {String} tabId the tab that this item activates.
4618 * @cfg {String} tagtype (a|span) render as a href or span?
4619 * @cfg {Boolean} animateRef (true|false) link to element default false
4622 * Create a new Navbar Item
4623 * @param {Object} config The config object
4625 Roo.bootstrap.NavItem = function(config){
4626 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4631 * The raw click event for the entire grid.
4632 * @param {Roo.EventObject} e
4637 * Fires when the active item active state changes
4638 * @param {Roo.bootstrap.NavItem} this
4639 * @param {boolean} state the new state
4645 * Fires when scroll to element
4646 * @param {Roo.bootstrap.NavItem} this
4647 * @param {Object} options
4648 * @param {Roo.EventObject} e
4656 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4665 preventDefault : false,
4673 getAutoCreate : function(){
4682 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4684 if (this.disabled) {
4685 cfg.cls += ' disabled';
4688 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4692 href : this.href || "#",
4693 html: this.html || ''
4696 if (this.tagtype == 'a') {
4697 cfg.cn[0].cls = 'nav-link';
4700 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4703 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>'
4705 if(this.glyphicon) {
4706 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4711 cfg.cn[0].html += " <span class='caret'></span>";
4715 if (this.badge !== '') {
4717 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4725 onRender : function(ct, position)
4727 // Roo.log("Call onRender: " + this.xtype);
4728 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4732 return Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4736 initEvents: function()
4738 if (typeof (this.menu) != 'undefined') {
4739 this.menu.parentType = this.xtype;
4740 this.menu.triggerEl = this.el;
4741 this.menu = this.addxtype(Roo.apply({}, this.menu));
4744 this.el.select('a',true).on('click', this.onClick, this);
4746 if(this.tagtype == 'span'){
4747 this.el.select('span',true).on('click', this.onClick, this);
4750 // at this point parent should be available..
4751 this.parent().register(this);
4754 onClick : function(e)
4756 if (e.getTarget('.dropdown-menu-item')) {
4757 // did you click on a menu itemm.... - then don't trigger onclick..
4762 this.preventDefault ||
4765 Roo.log("NavItem - prevent Default?");
4769 if (this.disabled) {
4773 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4774 if (tg && tg.transition) {
4775 Roo.log("waiting for the transitionend");
4781 //Roo.log("fire event clicked");
4782 if(this.fireEvent('click', this, e) === false){
4786 if(this.tagtype == 'span'){
4790 //Roo.log(this.href);
4791 var ael = this.el.select('a',true).first();
4794 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4795 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4796 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4797 return; // ignore... - it's a 'hash' to another page.
4799 Roo.log("NavItem - prevent Default?");
4801 this.scrollToElement(e);
4805 var p = this.parent();
4807 if (['tabs','pills'].indexOf(p.type)!==-1) {
4808 if (typeof(p.setActiveItem) !== 'undefined') {
4809 p.setActiveItem(this);
4813 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4814 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4815 // remove the collapsed menu expand...
4816 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4820 isActive: function () {
4823 setActive : function(state, fire, is_was_active)
4825 if (this.active && !state && this.navId) {
4826 this.was_active = true;
4827 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4829 nv.clearWasActive(this);
4833 this.active = state;
4836 this.el.removeClass('active');
4837 } else if (!this.el.hasClass('active')) {
4838 this.el.addClass('active');
4841 this.fireEvent('changed', this, state);
4844 // show a panel if it's registered and related..
4846 if (!this.navId || !this.tabId || !state || is_was_active) {
4850 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4854 var pan = tg.getPanelByName(this.tabId);
4858 // if we can not flip to new panel - go back to old nav highlight..
4859 if (false == tg.showPanel(pan)) {
4860 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4862 var onav = nv.getWasActive();
4864 onav.setActive(true, false, true);
4873 // this should not be here...
4874 setDisabled : function(state)
4876 this.disabled = state;
4878 this.el.removeClass('disabled');
4879 } else if (!this.el.hasClass('disabled')) {
4880 this.el.addClass('disabled');
4886 * Fetch the element to display the tooltip on.
4887 * @return {Roo.Element} defaults to this.el
4889 tooltipEl : function()
4891 return this.el.select('' + this.tagtype + '', true).first();
4894 scrollToElement : function(e)
4896 var c = document.body;
4899 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4901 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4902 c = document.documentElement;
4905 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4911 var o = target.calcOffsetsTo(c);
4918 this.fireEvent('scrollto', this, options, e);
4920 Roo.get(c).scrollTo('top', options.value, true);
4933 * <span> icon </span>
4934 * <span> text </span>
4935 * <span>badge </span>
4939 * @class Roo.bootstrap.NavSidebarItem
4940 * @extends Roo.bootstrap.NavItem
4941 * Bootstrap Navbar.NavSidebarItem class
4942 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4943 * {Boolean} open is the menu open
4944 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4945 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4946 * {String} buttonSize (sm|md|lg)the extra classes for the button
4947 * {Boolean} showArrow show arrow next to the text (default true)
4949 * Create a new Navbar Button
4950 * @param {Object} config The config object
4952 Roo.bootstrap.NavSidebarItem = function(config){
4953 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4958 * The raw click event for the entire grid.
4959 * @param {Roo.EventObject} e
4964 * Fires when the active item active state changes
4965 * @param {Roo.bootstrap.NavSidebarItem} this
4966 * @param {boolean} state the new state
4974 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4976 badgeWeight : 'default',
4982 buttonWeight : 'default',
4988 getAutoCreate : function(){
4993 href : this.href || '#',
4999 if(this.buttonView){
5002 href : this.href || '#',
5003 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5016 cfg.cls += ' active';
5019 if (this.disabled) {
5020 cfg.cls += ' disabled';
5023 cfg.cls += ' open x-open';
5026 if (this.glyphicon || this.icon) {
5027 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5028 a.cn.push({ tag : 'i', cls : c }) ;
5031 if(!this.buttonView){
5034 html : this.html || ''
5041 if (this.badge !== '') {
5042 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5048 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5051 a.cls += ' dropdown-toggle treeview' ;
5057 initEvents : function()
5059 if (typeof (this.menu) != 'undefined') {
5060 this.menu.parentType = this.xtype;
5061 this.menu.triggerEl = this.el;
5062 this.menu = this.addxtype(Roo.apply({}, this.menu));
5065 this.el.on('click', this.onClick, this);
5067 if(this.badge !== ''){
5068 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5073 onClick : function(e)
5080 if(this.preventDefault){
5084 this.fireEvent('click', this);
5087 disable : function()
5089 this.setDisabled(true);
5094 this.setDisabled(false);
5097 setDisabled : function(state)
5099 if(this.disabled == state){
5103 this.disabled = state;
5106 this.el.addClass('disabled');
5110 this.el.removeClass('disabled');
5115 setActive : function(state)
5117 if(this.active == state){
5121 this.active = state;
5124 this.el.addClass('active');
5128 this.el.removeClass('active');
5133 isActive: function ()
5138 setBadge : function(str)
5144 this.badgeEl.dom.innerHTML = str;
5161 * @class Roo.bootstrap.Row
5162 * @extends Roo.bootstrap.Component
5163 * Bootstrap Row class (contains columns...)
5167 * @param {Object} config The config object
5170 Roo.bootstrap.Row = function(config){
5171 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5174 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5176 getAutoCreate : function(){
5195 * @class Roo.bootstrap.Element
5196 * @extends Roo.bootstrap.Component
5197 * Bootstrap Element class
5198 * @cfg {String} html contents of the element
5199 * @cfg {String} tag tag of the element
5200 * @cfg {String} cls class of the element
5201 * @cfg {Boolean} preventDefault (true|false) default false
5202 * @cfg {Boolean} clickable (true|false) default false
5205 * Create a new Element
5206 * @param {Object} config The config object
5209 Roo.bootstrap.Element = function(config){
5210 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5216 * When a element is chick
5217 * @param {Roo.bootstrap.Element} this
5218 * @param {Roo.EventObject} e
5224 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5229 preventDefault: false,
5232 getAutoCreate : function(){
5236 // cls: this.cls, double assign in parent class Component.js :: onRender
5243 initEvents: function()
5245 Roo.bootstrap.Element.superclass.initEvents.call(this);
5248 this.el.on('click', this.onClick, this);
5253 onClick : function(e)
5255 if(this.preventDefault){
5259 this.fireEvent('click', this, e);
5262 getValue : function()
5264 return this.el.dom.innerHTML;
5267 setValue : function(value)
5269 this.el.dom.innerHTML = value;
5284 * @class Roo.bootstrap.Pagination
5285 * @extends Roo.bootstrap.Component
5286 * Bootstrap Pagination class
5287 * @cfg {String} size xs | sm | md | lg
5288 * @cfg {Boolean} inverse false | true
5291 * Create a new Pagination
5292 * @param {Object} config The config object
5295 Roo.bootstrap.Pagination = function(config){
5296 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5299 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5305 getAutoCreate : function(){
5311 cfg.cls += ' inverse';
5317 cfg.cls += " " + this.cls;
5335 * @class Roo.bootstrap.PaginationItem
5336 * @extends Roo.bootstrap.Component
5337 * Bootstrap PaginationItem class
5338 * @cfg {String} html text
5339 * @cfg {String} href the link
5340 * @cfg {Boolean} preventDefault (true | false) default true
5341 * @cfg {Boolean} active (true | false) default false
5342 * @cfg {Boolean} disabled default false
5346 * Create a new PaginationItem
5347 * @param {Object} config The config object
5351 Roo.bootstrap.PaginationItem = function(config){
5352 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5357 * The raw click event for the entire grid.
5358 * @param {Roo.EventObject} e
5364 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5368 preventDefault: true,
5373 getAutoCreate : function(){
5379 href : this.href ? this.href : '#',
5380 html : this.html ? this.html : ''
5390 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5394 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5400 initEvents: function() {
5402 this.el.on('click', this.onClick, this);
5405 onClick : function(e)
5407 Roo.log('PaginationItem on click ');
5408 if(this.preventDefault){
5416 this.fireEvent('click', this, e);
5432 * @class Roo.bootstrap.Slider
5433 * @extends Roo.bootstrap.Component
5434 * Bootstrap Slider class
5437 * Create a new Slider
5438 * @param {Object} config The config object
5441 Roo.bootstrap.Slider = function(config){
5442 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5445 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5447 getAutoCreate : function(){
5451 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5455 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5467 * Ext JS Library 1.1.1
5468 * Copyright(c) 2006-2007, Ext JS, LLC.
5470 * Originally Released Under LGPL - original licence link has changed is not relivant.
5473 * <script type="text/javascript">
5478 * @class Roo.grid.ColumnModel
5479 * @extends Roo.util.Observable
5480 * This is the default implementation of a ColumnModel used by the Grid. It defines
5481 * the columns in the grid.
5484 var colModel = new Roo.grid.ColumnModel([
5485 {header: "Ticker", width: 60, sortable: true, locked: true},
5486 {header: "Company Name", width: 150, sortable: true},
5487 {header: "Market Cap.", width: 100, sortable: true},
5488 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5489 {header: "Employees", width: 100, sortable: true, resizable: false}
5494 * The config options listed for this class are options which may appear in each
5495 * individual column definition.
5496 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5498 * @param {Object} config An Array of column config objects. See this class's
5499 * config objects for details.
5501 Roo.grid.ColumnModel = function(config){
5503 * The config passed into the constructor
5505 this.config = config;
5508 // if no id, create one
5509 // if the column does not have a dataIndex mapping,
5510 // map it to the order it is in the config
5511 for(var i = 0, len = config.length; i < len; i++){
5513 if(typeof c.dataIndex == "undefined"){
5516 if(typeof c.renderer == "string"){
5517 c.renderer = Roo.util.Format[c.renderer];
5519 if(typeof c.id == "undefined"){
5522 if(c.editor && c.editor.xtype){
5523 c.editor = Roo.factory(c.editor, Roo.grid);
5525 if(c.editor && c.editor.isFormField){
5526 c.editor = new Roo.grid.GridEditor(c.editor);
5528 this.lookup[c.id] = c;
5532 * The width of columns which have no width specified (defaults to 100)
5535 this.defaultWidth = 100;
5538 * Default sortable of columns which have no sortable specified (defaults to false)
5541 this.defaultSortable = false;
5545 * @event widthchange
5546 * Fires when the width of a column changes.
5547 * @param {ColumnModel} this
5548 * @param {Number} columnIndex The column index
5549 * @param {Number} newWidth The new width
5551 "widthchange": true,
5553 * @event headerchange
5554 * Fires when the text of a header changes.
5555 * @param {ColumnModel} this
5556 * @param {Number} columnIndex The column index
5557 * @param {Number} newText The new header text
5559 "headerchange": true,
5561 * @event hiddenchange
5562 * Fires when a column is hidden or "unhidden".
5563 * @param {ColumnModel} this
5564 * @param {Number} columnIndex The column index
5565 * @param {Boolean} hidden true if hidden, false otherwise
5567 "hiddenchange": true,
5569 * @event columnmoved
5570 * Fires when a column is moved.
5571 * @param {ColumnModel} this
5572 * @param {Number} oldIndex
5573 * @param {Number} newIndex
5575 "columnmoved" : true,
5577 * @event columlockchange
5578 * Fires when a column's locked state is changed
5579 * @param {ColumnModel} this
5580 * @param {Number} colIndex
5581 * @param {Boolean} locked true if locked
5583 "columnlockchange" : true
5585 Roo.grid.ColumnModel.superclass.constructor.call(this);
5587 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5589 * @cfg {String} header The header text to display in the Grid view.
5592 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5593 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5594 * specified, the column's index is used as an index into the Record's data Array.
5597 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5598 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5601 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5602 * Defaults to the value of the {@link #defaultSortable} property.
5603 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5606 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5609 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5612 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5615 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5618 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5619 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5620 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5621 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5624 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5627 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5630 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5633 * @cfg {String} cursor (Optional)
5636 * @cfg {String} tooltip (Optional)
5639 * @cfg {Number} xs (Optional)
5642 * @cfg {Number} sm (Optional)
5645 * @cfg {Number} md (Optional)
5648 * @cfg {Number} lg (Optional)
5651 * Returns the id of the column at the specified index.
5652 * @param {Number} index The column index
5653 * @return {String} the id
5655 getColumnId : function(index){
5656 return this.config[index].id;
5660 * Returns the column for a specified id.
5661 * @param {String} id The column id
5662 * @return {Object} the column
5664 getColumnById : function(id){
5665 return this.lookup[id];
5670 * Returns the column for a specified dataIndex.
5671 * @param {String} dataIndex The column dataIndex
5672 * @return {Object|Boolean} the column or false if not found
5674 getColumnByDataIndex: function(dataIndex){
5675 var index = this.findColumnIndex(dataIndex);
5676 return index > -1 ? this.config[index] : false;
5680 * Returns the index for a specified column id.
5681 * @param {String} id The column id
5682 * @return {Number} the index, or -1 if not found
5684 getIndexById : function(id){
5685 for(var i = 0, len = this.config.length; i < len; i++){
5686 if(this.config[i].id == id){
5694 * Returns the index for a specified column dataIndex.
5695 * @param {String} dataIndex The column dataIndex
5696 * @return {Number} the index, or -1 if not found
5699 findColumnIndex : function(dataIndex){
5700 for(var i = 0, len = this.config.length; i < len; i++){
5701 if(this.config[i].dataIndex == dataIndex){
5709 moveColumn : function(oldIndex, newIndex){
5710 var c = this.config[oldIndex];
5711 this.config.splice(oldIndex, 1);
5712 this.config.splice(newIndex, 0, c);
5713 this.dataMap = null;
5714 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5717 isLocked : function(colIndex){
5718 return this.config[colIndex].locked === true;
5721 setLocked : function(colIndex, value, suppressEvent){
5722 if(this.isLocked(colIndex) == value){
5725 this.config[colIndex].locked = value;
5727 this.fireEvent("columnlockchange", this, colIndex, value);
5731 getTotalLockedWidth : function(){
5733 for(var i = 0; i < this.config.length; i++){
5734 if(this.isLocked(i) && !this.isHidden(i)){
5735 this.totalWidth += this.getColumnWidth(i);
5741 getLockedCount : function(){
5742 for(var i = 0, len = this.config.length; i < len; i++){
5743 if(!this.isLocked(i)){
5748 return this.config.length;
5752 * Returns the number of columns.
5755 getColumnCount : function(visibleOnly){
5756 if(visibleOnly === true){
5758 for(var i = 0, len = this.config.length; i < len; i++){
5759 if(!this.isHidden(i)){
5765 return this.config.length;
5769 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5770 * @param {Function} fn
5771 * @param {Object} scope (optional)
5772 * @return {Array} result
5774 getColumnsBy : function(fn, scope){
5776 for(var i = 0, len = this.config.length; i < len; i++){
5777 var c = this.config[i];
5778 if(fn.call(scope||this, c, i) === true){
5786 * Returns true if the specified column is sortable.
5787 * @param {Number} col The column index
5790 isSortable : function(col){
5791 if(typeof this.config[col].sortable == "undefined"){
5792 return this.defaultSortable;
5794 return this.config[col].sortable;
5798 * Returns the rendering (formatting) function defined for the column.
5799 * @param {Number} col The column index.
5800 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5802 getRenderer : function(col){
5803 if(!this.config[col].renderer){
5804 return Roo.grid.ColumnModel.defaultRenderer;
5806 return this.config[col].renderer;
5810 * Sets the rendering (formatting) function for a column.
5811 * @param {Number} col The column index
5812 * @param {Function} fn The function to use to process the cell's raw data
5813 * to return HTML markup for the grid view. The render function is called with
5814 * the following parameters:<ul>
5815 * <li>Data value.</li>
5816 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5817 * <li>css A CSS style string to apply to the table cell.</li>
5818 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5819 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5820 * <li>Row index</li>
5821 * <li>Column index</li>
5822 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5824 setRenderer : function(col, fn){
5825 this.config[col].renderer = fn;
5829 * Returns the width for the specified column.
5830 * @param {Number} col The column index
5833 getColumnWidth : function(col){
5834 return this.config[col].width * 1 || this.defaultWidth;
5838 * Sets the width for a column.
5839 * @param {Number} col The column index
5840 * @param {Number} width The new width
5842 setColumnWidth : function(col, width, suppressEvent){
5843 this.config[col].width = width;
5844 this.totalWidth = null;
5846 this.fireEvent("widthchange", this, col, width);
5851 * Returns the total width of all columns.
5852 * @param {Boolean} includeHidden True to include hidden column widths
5855 getTotalWidth : function(includeHidden){
5856 if(!this.totalWidth){
5857 this.totalWidth = 0;
5858 for(var i = 0, len = this.config.length; i < len; i++){
5859 if(includeHidden || !this.isHidden(i)){
5860 this.totalWidth += this.getColumnWidth(i);
5864 return this.totalWidth;
5868 * Returns the header for the specified column.
5869 * @param {Number} col The column index
5872 getColumnHeader : function(col){
5873 return this.config[col].header;
5877 * Sets the header for a column.
5878 * @param {Number} col The column index
5879 * @param {String} header The new header
5881 setColumnHeader : function(col, header){
5882 this.config[col].header = header;
5883 this.fireEvent("headerchange", this, col, header);
5887 * Returns the tooltip for the specified column.
5888 * @param {Number} col The column index
5891 getColumnTooltip : function(col){
5892 return this.config[col].tooltip;
5895 * Sets the tooltip for a column.
5896 * @param {Number} col The column index
5897 * @param {String} tooltip The new tooltip
5899 setColumnTooltip : function(col, tooltip){
5900 this.config[col].tooltip = tooltip;
5904 * Returns the dataIndex for the specified column.
5905 * @param {Number} col The column index
5908 getDataIndex : function(col){
5909 return this.config[col].dataIndex;
5913 * Sets the dataIndex for a column.
5914 * @param {Number} col The column index
5915 * @param {Number} dataIndex The new dataIndex
5917 setDataIndex : function(col, dataIndex){
5918 this.config[col].dataIndex = dataIndex;
5924 * Returns true if the cell is editable.
5925 * @param {Number} colIndex The column index
5926 * @param {Number} rowIndex The row index - this is nto actually used..?
5929 isCellEditable : function(colIndex, rowIndex){
5930 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5934 * Returns the editor defined for the cell/column.
5935 * return false or null to disable editing.
5936 * @param {Number} colIndex The column index
5937 * @param {Number} rowIndex The row index
5940 getCellEditor : function(colIndex, rowIndex){
5941 return this.config[colIndex].editor;
5945 * Sets if a column is editable.
5946 * @param {Number} col The column index
5947 * @param {Boolean} editable True if the column is editable
5949 setEditable : function(col, editable){
5950 this.config[col].editable = editable;
5955 * Returns true if the column is hidden.
5956 * @param {Number} colIndex The column index
5959 isHidden : function(colIndex){
5960 return this.config[colIndex].hidden;
5965 * Returns true if the column width cannot be changed
5967 isFixed : function(colIndex){
5968 return this.config[colIndex].fixed;
5972 * Returns true if the column can be resized
5975 isResizable : function(colIndex){
5976 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5979 * Sets if a column is hidden.
5980 * @param {Number} colIndex The column index
5981 * @param {Boolean} hidden True if the column is hidden
5983 setHidden : function(colIndex, hidden){
5984 this.config[colIndex].hidden = hidden;
5985 this.totalWidth = null;
5986 this.fireEvent("hiddenchange", this, colIndex, hidden);
5990 * Sets the editor for a column.
5991 * @param {Number} col The column index
5992 * @param {Object} editor The editor object
5994 setEditor : function(col, editor){
5995 this.config[col].editor = editor;
5999 Roo.grid.ColumnModel.defaultRenderer = function(value)
6001 if(typeof value == "object") {
6004 if(typeof value == "string" && value.length < 1){
6008 return String.format("{0}", value);
6011 // Alias for backwards compatibility
6012 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6015 * Ext JS Library 1.1.1
6016 * Copyright(c) 2006-2007, Ext JS, LLC.
6018 * Originally Released Under LGPL - original licence link has changed is not relivant.
6021 * <script type="text/javascript">
6025 * @class Roo.LoadMask
6026 * A simple utility class for generically masking elements while loading data. If the element being masked has
6027 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6028 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6029 * element's UpdateManager load indicator and will be destroyed after the initial load.
6031 * Create a new LoadMask
6032 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6033 * @param {Object} config The config object
6035 Roo.LoadMask = function(el, config){
6036 this.el = Roo.get(el);
6037 Roo.apply(this, config);
6039 this.store.on('beforeload', this.onBeforeLoad, this);
6040 this.store.on('load', this.onLoad, this);
6041 this.store.on('loadexception', this.onLoadException, this);
6042 this.removeMask = false;
6044 var um = this.el.getUpdateManager();
6045 um.showLoadIndicator = false; // disable the default indicator
6046 um.on('beforeupdate', this.onBeforeLoad, this);
6047 um.on('update', this.onLoad, this);
6048 um.on('failure', this.onLoad, this);
6049 this.removeMask = true;
6053 Roo.LoadMask.prototype = {
6055 * @cfg {Boolean} removeMask
6056 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6057 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6061 * The text to display in a centered loading message box (defaults to 'Loading...')
6065 * @cfg {String} msgCls
6066 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6068 msgCls : 'x-mask-loading',
6071 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6077 * Disables the mask to prevent it from being displayed
6079 disable : function(){
6080 this.disabled = true;
6084 * Enables the mask so that it can be displayed
6086 enable : function(){
6087 this.disabled = false;
6090 onLoadException : function()
6094 if (typeof(arguments[3]) != 'undefined') {
6095 Roo.MessageBox.alert("Error loading",arguments[3]);
6099 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6100 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6107 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6112 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6116 onBeforeLoad : function(){
6118 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6123 destroy : function(){
6125 this.store.un('beforeload', this.onBeforeLoad, this);
6126 this.store.un('load', this.onLoad, this);
6127 this.store.un('loadexception', this.onLoadException, this);
6129 var um = this.el.getUpdateManager();
6130 um.un('beforeupdate', this.onBeforeLoad, this);
6131 um.un('update', this.onLoad, this);
6132 um.un('failure', this.onLoad, this);
6143 * @class Roo.bootstrap.Table
6144 * @extends Roo.bootstrap.Component
6145 * Bootstrap Table class
6146 * @cfg {String} cls table class
6147 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6148 * @cfg {String} bgcolor Specifies the background color for a table
6149 * @cfg {Number} border Specifies whether the table cells should have borders or not
6150 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6151 * @cfg {Number} cellspacing Specifies the space between cells
6152 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6153 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6154 * @cfg {String} sortable Specifies that the table should be sortable
6155 * @cfg {String} summary Specifies a summary of the content of a table
6156 * @cfg {Number} width Specifies the width of a table
6157 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6159 * @cfg {boolean} striped Should the rows be alternative striped
6160 * @cfg {boolean} bordered Add borders to the table
6161 * @cfg {boolean} hover Add hover highlighting
6162 * @cfg {boolean} condensed Format condensed
6163 * @cfg {boolean} responsive Format condensed
6164 * @cfg {Boolean} loadMask (true|false) default false
6165 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6166 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6167 * @cfg {Boolean} rowSelection (true|false) default false
6168 * @cfg {Boolean} cellSelection (true|false) default false
6169 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6170 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6171 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6172 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6176 * Create a new Table
6177 * @param {Object} config The config object
6180 Roo.bootstrap.Table = function(config){
6181 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6186 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6187 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6188 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6189 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6191 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6193 this.sm.grid = this;
6194 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6195 this.sm = this.selModel;
6196 this.sm.xmodule = this.xmodule || false;
6199 if (this.cm && typeof(this.cm.config) == 'undefined') {
6200 this.colModel = new Roo.grid.ColumnModel(this.cm);
6201 this.cm = this.colModel;
6202 this.cm.xmodule = this.xmodule || false;
6205 this.store= Roo.factory(this.store, Roo.data);
6206 this.ds = this.store;
6207 this.ds.xmodule = this.xmodule || false;
6210 if (this.footer && this.store) {
6211 this.footer.dataSource = this.ds;
6212 this.footer = Roo.factory(this.footer);
6219 * Fires when a cell is clicked
6220 * @param {Roo.bootstrap.Table} this
6221 * @param {Roo.Element} el
6222 * @param {Number} rowIndex
6223 * @param {Number} columnIndex
6224 * @param {Roo.EventObject} e
6228 * @event celldblclick
6229 * Fires when a cell is double clicked
6230 * @param {Roo.bootstrap.Table} this
6231 * @param {Roo.Element} el
6232 * @param {Number} rowIndex
6233 * @param {Number} columnIndex
6234 * @param {Roo.EventObject} e
6236 "celldblclick" : true,
6239 * Fires when a row is clicked
6240 * @param {Roo.bootstrap.Table} this
6241 * @param {Roo.Element} el
6242 * @param {Number} rowIndex
6243 * @param {Roo.EventObject} e
6247 * @event rowdblclick
6248 * Fires when a row is double clicked
6249 * @param {Roo.bootstrap.Table} this
6250 * @param {Roo.Element} el
6251 * @param {Number} rowIndex
6252 * @param {Roo.EventObject} e
6254 "rowdblclick" : true,
6257 * Fires when a mouseover occur
6258 * @param {Roo.bootstrap.Table} this
6259 * @param {Roo.Element} el
6260 * @param {Number} rowIndex
6261 * @param {Number} columnIndex
6262 * @param {Roo.EventObject} e
6267 * Fires when a mouseout occur
6268 * @param {Roo.bootstrap.Table} this
6269 * @param {Roo.Element} el
6270 * @param {Number} rowIndex
6271 * @param {Number} columnIndex
6272 * @param {Roo.EventObject} e
6277 * Fires when a row is rendered, so you can change add a style to it.
6278 * @param {Roo.bootstrap.Table} this
6279 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6283 * @event rowsrendered
6284 * Fires when all the rows have been rendered
6285 * @param {Roo.bootstrap.Table} this
6287 'rowsrendered' : true,
6289 * @event contextmenu
6290 * The raw contextmenu event for the entire grid.
6291 * @param {Roo.EventObject} e
6293 "contextmenu" : true,
6295 * @event rowcontextmenu
6296 * Fires when a row is right clicked
6297 * @param {Roo.bootstrap.Table} this
6298 * @param {Number} rowIndex
6299 * @param {Roo.EventObject} e
6301 "rowcontextmenu" : true,
6303 * @event cellcontextmenu
6304 * Fires when a cell is right clicked
6305 * @param {Roo.bootstrap.Table} this
6306 * @param {Number} rowIndex
6307 * @param {Number} cellIndex
6308 * @param {Roo.EventObject} e
6310 "cellcontextmenu" : true,
6312 * @event headercontextmenu
6313 * Fires when a header is right clicked
6314 * @param {Roo.bootstrap.Table} this
6315 * @param {Number} columnIndex
6316 * @param {Roo.EventObject} e
6318 "headercontextmenu" : true
6322 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6348 rowSelection : false,
6349 cellSelection : false,
6352 // Roo.Element - the tbody
6354 // Roo.Element - thead element
6357 container: false, // used by gridpanel...
6363 auto_hide_footer : false,
6365 getAutoCreate : function()
6367 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6374 if (this.scrollBody) {
6375 cfg.cls += ' table-body-fixed';
6378 cfg.cls += ' table-striped';
6382 cfg.cls += ' table-hover';
6384 if (this.bordered) {
6385 cfg.cls += ' table-bordered';
6387 if (this.condensed) {
6388 cfg.cls += ' table-condensed';
6390 if (this.responsive) {
6391 cfg.cls += ' table-responsive';
6395 cfg.cls+= ' ' +this.cls;
6398 // this lot should be simplifed...
6411 ].forEach(function(k) {
6419 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6422 if(this.store || this.cm){
6423 if(this.headerShow){
6424 cfg.cn.push(this.renderHeader());
6427 cfg.cn.push(this.renderBody());
6429 if(this.footerShow){
6430 cfg.cn.push(this.renderFooter());
6432 // where does this come from?
6433 //cfg.cls+= ' TableGrid';
6436 return { cn : [ cfg ] };
6439 initEvents : function()
6441 if(!this.store || !this.cm){
6444 if (this.selModel) {
6445 this.selModel.initEvents();
6449 //Roo.log('initEvents with ds!!!!');
6451 this.mainBody = this.el.select('tbody', true).first();
6452 this.mainHead = this.el.select('thead', true).first();
6453 this.mainFoot = this.el.select('tfoot', true).first();
6459 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6460 e.on('click', _this.sort, _this);
6463 this.mainBody.on("click", this.onClick, this);
6464 this.mainBody.on("dblclick", this.onDblClick, this);
6466 // why is this done????? = it breaks dialogs??
6467 //this.parent().el.setStyle('position', 'relative');
6471 this.footer.parentId = this.id;
6472 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6475 this.el.select('tfoot tr td').first().addClass('hide');
6480 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6483 this.store.on('load', this.onLoad, this);
6484 this.store.on('beforeload', this.onBeforeLoad, this);
6485 this.store.on('update', this.onUpdate, this);
6486 this.store.on('add', this.onAdd, this);
6487 this.store.on("clear", this.clear, this);
6489 this.el.on("contextmenu", this.onContextMenu, this);
6491 this.mainBody.on('scroll', this.onBodyScroll, this);
6493 this.cm.on("headerchange", this.onHeaderChange, this);
6495 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6499 onContextMenu : function(e, t)
6501 this.processEvent("contextmenu", e);
6504 processEvent : function(name, e)
6506 if (name != 'touchstart' ) {
6507 this.fireEvent(name, e);
6510 var t = e.getTarget();
6512 var cell = Roo.get(t);
6518 if(cell.findParent('tfoot', false, true)){
6522 if(cell.findParent('thead', false, true)){
6524 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6525 cell = Roo.get(t).findParent('th', false, true);
6527 Roo.log("failed to find th in thead?");
6528 Roo.log(e.getTarget());
6533 var cellIndex = cell.dom.cellIndex;
6535 var ename = name == 'touchstart' ? 'click' : name;
6536 this.fireEvent("header" + ename, this, cellIndex, e);
6541 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6542 cell = Roo.get(t).findParent('td', false, true);
6544 Roo.log("failed to find th in tbody?");
6545 Roo.log(e.getTarget());
6550 var row = cell.findParent('tr', false, true);
6551 var cellIndex = cell.dom.cellIndex;
6552 var rowIndex = row.dom.rowIndex - 1;
6556 this.fireEvent("row" + name, this, rowIndex, e);
6560 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6566 onMouseover : function(e, el)
6568 var cell = Roo.get(el);
6574 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6575 cell = cell.findParent('td', false, true);
6578 var row = cell.findParent('tr', false, true);
6579 var cellIndex = cell.dom.cellIndex;
6580 var rowIndex = row.dom.rowIndex - 1; // start from 0
6582 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6586 onMouseout : function(e, el)
6588 var cell = Roo.get(el);
6594 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6595 cell = cell.findParent('td', false, true);
6598 var row = cell.findParent('tr', false, true);
6599 var cellIndex = cell.dom.cellIndex;
6600 var rowIndex = row.dom.rowIndex - 1; // start from 0
6602 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6606 onClick : function(e, el)
6608 var cell = Roo.get(el);
6610 if(!cell || (!this.cellSelection && !this.rowSelection)){
6614 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6615 cell = cell.findParent('td', false, true);
6618 if(!cell || typeof(cell) == 'undefined'){
6622 var row = cell.findParent('tr', false, true);
6624 if(!row || typeof(row) == 'undefined'){
6628 var cellIndex = cell.dom.cellIndex;
6629 var rowIndex = this.getRowIndex(row);
6631 // why??? - should these not be based on SelectionModel?
6632 if(this.cellSelection){
6633 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6636 if(this.rowSelection){
6637 this.fireEvent('rowclick', this, row, rowIndex, e);
6643 onDblClick : function(e,el)
6645 var cell = Roo.get(el);
6647 if(!cell || (!this.cellSelection && !this.rowSelection)){
6651 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6652 cell = cell.findParent('td', false, true);
6655 if(!cell || typeof(cell) == 'undefined'){
6659 var row = cell.findParent('tr', false, true);
6661 if(!row || typeof(row) == 'undefined'){
6665 var cellIndex = cell.dom.cellIndex;
6666 var rowIndex = this.getRowIndex(row);
6668 if(this.cellSelection){
6669 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6672 if(this.rowSelection){
6673 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6677 sort : function(e,el)
6679 var col = Roo.get(el);
6681 if(!col.hasClass('sortable')){
6685 var sort = col.attr('sort');
6688 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6692 this.store.sortInfo = {field : sort, direction : dir};
6695 Roo.log("calling footer first");
6696 this.footer.onClick('first');
6699 this.store.load({ params : { start : 0 } });
6703 renderHeader : function()
6711 this.totalWidth = 0;
6713 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6715 var config = cm.config[i];
6719 cls : 'x-hcol-' + i,
6721 html: cm.getColumnHeader(i)
6726 if(typeof(config.sortable) != 'undefined' && config.sortable){
6728 c.html = '<i class="glyphicon"></i>' + c.html;
6731 if(typeof(config.lgHeader) != 'undefined'){
6732 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6735 if(typeof(config.mdHeader) != 'undefined'){
6736 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6739 if(typeof(config.smHeader) != 'undefined'){
6740 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6743 if(typeof(config.xsHeader) != 'undefined'){
6744 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6751 if(typeof(config.tooltip) != 'undefined'){
6752 c.tooltip = config.tooltip;
6755 if(typeof(config.colspan) != 'undefined'){
6756 c.colspan = config.colspan;
6759 if(typeof(config.hidden) != 'undefined' && config.hidden){
6760 c.style += ' display:none;';
6763 if(typeof(config.dataIndex) != 'undefined'){
6764 c.sort = config.dataIndex;
6769 if(typeof(config.align) != 'undefined' && config.align.length){
6770 c.style += ' text-align:' + config.align + ';';
6773 if(typeof(config.width) != 'undefined'){
6774 c.style += ' width:' + config.width + 'px;';
6775 this.totalWidth += config.width;
6777 this.totalWidth += 100; // assume minimum of 100 per column?
6780 if(typeof(config.cls) != 'undefined'){
6781 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6784 ['xs','sm','md','lg'].map(function(size){
6786 if(typeof(config[size]) == 'undefined'){
6790 if (!config[size]) { // 0 = hidden
6791 c.cls += ' hidden-' + size;
6795 c.cls += ' col-' + size + '-' + config[size];
6805 renderBody : function()
6815 colspan : this.cm.getColumnCount()
6825 renderFooter : function()
6835 colspan : this.cm.getColumnCount()
6849 // Roo.log('ds onload');
6854 var ds = this.store;
6856 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6857 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6858 if (_this.store.sortInfo) {
6860 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6861 e.select('i', true).addClass(['glyphicon-arrow-up']);
6864 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6865 e.select('i', true).addClass(['glyphicon-arrow-down']);
6870 var tbody = this.mainBody;
6872 if(ds.getCount() > 0){
6873 ds.data.each(function(d,rowIndex){
6874 var row = this.renderRow(cm, ds, rowIndex);
6876 tbody.createChild(row);
6880 if(row.cellObjects.length){
6881 Roo.each(row.cellObjects, function(r){
6882 _this.renderCellObject(r);
6889 var tfoot = this.el.select('tfoot', true).first();
6891 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6893 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6895 var total = this.ds.getTotalCount();
6897 if(this.footer.pageSize < total){
6898 this.mainFoot.show();
6902 Roo.each(this.el.select('tbody td', true).elements, function(e){
6903 e.on('mouseover', _this.onMouseover, _this);
6906 Roo.each(this.el.select('tbody td', true).elements, function(e){
6907 e.on('mouseout', _this.onMouseout, _this);
6909 this.fireEvent('rowsrendered', this);
6915 onUpdate : function(ds,record)
6917 this.refreshRow(record);
6921 onRemove : function(ds, record, index, isUpdate){
6922 if(isUpdate !== true){
6923 this.fireEvent("beforerowremoved", this, index, record);
6925 var bt = this.mainBody.dom;
6927 var rows = this.el.select('tbody > tr', true).elements;
6929 if(typeof(rows[index]) != 'undefined'){
6930 bt.removeChild(rows[index].dom);
6933 // if(bt.rows[index]){
6934 // bt.removeChild(bt.rows[index]);
6937 if(isUpdate !== true){
6938 //this.stripeRows(index);
6939 //this.syncRowHeights(index, index);
6941 this.fireEvent("rowremoved", this, index, record);
6945 onAdd : function(ds, records, rowIndex)
6947 //Roo.log('on Add called');
6948 // - note this does not handle multiple adding very well..
6949 var bt = this.mainBody.dom;
6950 for (var i =0 ; i < records.length;i++) {
6951 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6952 //Roo.log(records[i]);
6953 //Roo.log(this.store.getAt(rowIndex+i));
6954 this.insertRow(this.store, rowIndex + i, false);
6961 refreshRow : function(record){
6962 var ds = this.store, index;
6963 if(typeof record == 'number'){
6965 record = ds.getAt(index);
6967 index = ds.indexOf(record);
6969 this.insertRow(ds, index, true);
6971 this.onRemove(ds, record, index+1, true);
6973 //this.syncRowHeights(index, index);
6975 this.fireEvent("rowupdated", this, index, record);
6978 insertRow : function(dm, rowIndex, isUpdate){
6981 this.fireEvent("beforerowsinserted", this, rowIndex);
6983 //var s = this.getScrollState();
6984 var row = this.renderRow(this.cm, this.store, rowIndex);
6985 // insert before rowIndex..
6986 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6990 if(row.cellObjects.length){
6991 Roo.each(row.cellObjects, function(r){
6992 _this.renderCellObject(r);
6997 this.fireEvent("rowsinserted", this, rowIndex);
6998 //this.syncRowHeights(firstRow, lastRow);
6999 //this.stripeRows(firstRow);
7006 getRowDom : function(rowIndex)
7008 var rows = this.el.select('tbody > tr', true).elements;
7010 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7013 // returns the object tree for a tr..
7016 renderRow : function(cm, ds, rowIndex)
7018 var d = ds.getAt(rowIndex);
7022 cls : 'x-row-' + rowIndex,
7026 var cellObjects = [];
7028 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7029 var config = cm.config[i];
7031 var renderer = cm.getRenderer(i);
7035 if(typeof(renderer) !== 'undefined'){
7036 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7038 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7039 // and are rendered into the cells after the row is rendered - using the id for the element.
7041 if(typeof(value) === 'object'){
7051 rowIndex : rowIndex,
7056 this.fireEvent('rowclass', this, rowcfg);
7060 cls : rowcfg.rowClass + ' x-col-' + i,
7062 html: (typeof(value) === 'object') ? '' : value
7069 if(typeof(config.colspan) != 'undefined'){
7070 td.colspan = config.colspan;
7073 if(typeof(config.hidden) != 'undefined' && config.hidden){
7074 td.style += ' display:none;';
7077 if(typeof(config.align) != 'undefined' && config.align.length){
7078 td.style += ' text-align:' + config.align + ';';
7080 if(typeof(config.valign) != 'undefined' && config.valign.length){
7081 td.style += ' vertical-align:' + config.valign + ';';
7084 if(typeof(config.width) != 'undefined'){
7085 td.style += ' width:' + config.width + 'px;';
7088 if(typeof(config.cursor) != 'undefined'){
7089 td.style += ' cursor:' + config.cursor + ';';
7092 if(typeof(config.cls) != 'undefined'){
7093 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7096 ['xs','sm','md','lg'].map(function(size){
7098 if(typeof(config[size]) == 'undefined'){
7102 if (!config[size]) { // 0 = hidden
7103 td.cls += ' hidden-' + size;
7107 td.cls += ' col-' + size + '-' + config[size];
7115 row.cellObjects = cellObjects;
7123 onBeforeLoad : function()
7132 this.el.select('tbody', true).first().dom.innerHTML = '';
7135 * Show or hide a row.
7136 * @param {Number} rowIndex to show or hide
7137 * @param {Boolean} state hide
7139 setRowVisibility : function(rowIndex, state)
7141 var bt = this.mainBody.dom;
7143 var rows = this.el.select('tbody > tr', true).elements;
7145 if(typeof(rows[rowIndex]) == 'undefined'){
7148 rows[rowIndex].dom.style.display = state ? '' : 'none';
7152 getSelectionModel : function(){
7154 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7156 return this.selModel;
7159 * Render the Roo.bootstrap object from renderder
7161 renderCellObject : function(r)
7165 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7167 var t = r.cfg.render(r.container);
7170 Roo.each(r.cfg.cn, function(c){
7172 container: t.getChildContainer(),
7175 _this.renderCellObject(child);
7180 getRowIndex : function(row)
7184 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7195 * Returns the grid's underlying element = used by panel.Grid
7196 * @return {Element} The element
7198 getGridEl : function(){
7202 * Forces a resize - used by panel.Grid
7203 * @return {Element} The element
7205 autoSize : function()
7207 //var ctr = Roo.get(this.container.dom.parentElement);
7208 var ctr = Roo.get(this.el.dom);
7210 var thd = this.getGridEl().select('thead',true).first();
7211 var tbd = this.getGridEl().select('tbody', true).first();
7212 var tfd = this.getGridEl().select('tfoot', true).first();
7214 var cw = ctr.getWidth();
7218 tbd.setSize(ctr.getWidth(),
7219 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7221 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7224 cw = Math.max(cw, this.totalWidth);
7225 this.getGridEl().select('tr',true).setWidth(cw);
7226 // resize 'expandable coloumn?
7228 return; // we doe not have a view in this design..
7231 onBodyScroll: function()
7233 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7235 this.mainHead.setStyle({
7236 'position' : 'relative',
7237 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7243 var scrollHeight = this.mainBody.dom.scrollHeight;
7245 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7247 var height = this.mainBody.getHeight();
7249 if(scrollHeight - height == scrollTop) {
7251 var total = this.ds.getTotalCount();
7253 if(this.footer.cursor + this.footer.pageSize < total){
7255 this.footer.ds.load({
7257 start : this.footer.cursor + this.footer.pageSize,
7258 limit : this.footer.pageSize
7268 onHeaderChange : function()
7270 var header = this.renderHeader();
7271 var table = this.el.select('table', true).first();
7273 this.mainHead.remove();
7274 this.mainHead = table.createChild(header, this.mainBody, false);
7277 onHiddenChange : function(colModel, colIndex, hidden)
7279 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7280 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7282 this.CSS.updateRule(thSelector, "display", "");
7283 this.CSS.updateRule(tdSelector, "display", "");
7286 this.CSS.updateRule(thSelector, "display", "none");
7287 this.CSS.updateRule(tdSelector, "display", "none");
7290 this.onHeaderChange();
7294 setColumnWidth: function(col_index, width)
7296 // width = "md-2 xs-2..."
7297 if(!this.colModel.config[col_index]) {
7301 var w = width.split(" ");
7303 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7305 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7308 for(var j = 0; j < w.length; j++) {
7314 var size_cls = w[j].split("-");
7316 if(!Number.isInteger(size_cls[1] * 1)) {
7320 if(!this.colModel.config[col_index][size_cls[0]]) {
7324 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7328 h_row[0].classList.replace(
7329 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7330 "col-"+size_cls[0]+"-"+size_cls[1]
7333 for(var i = 0; i < rows.length; i++) {
7335 var size_cls = w[j].split("-");
7337 if(!Number.isInteger(size_cls[1] * 1)) {
7341 if(!this.colModel.config[col_index][size_cls[0]]) {
7345 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7349 rows[i].classList.replace(
7350 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7351 "col-"+size_cls[0]+"-"+size_cls[1]
7355 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7370 * @class Roo.bootstrap.TableCell
7371 * @extends Roo.bootstrap.Component
7372 * Bootstrap TableCell class
7373 * @cfg {String} html cell contain text
7374 * @cfg {String} cls cell class
7375 * @cfg {String} tag cell tag (td|th) default td
7376 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7377 * @cfg {String} align Aligns the content in a cell
7378 * @cfg {String} axis Categorizes cells
7379 * @cfg {String} bgcolor Specifies the background color of a cell
7380 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7381 * @cfg {Number} colspan Specifies the number of columns a cell should span
7382 * @cfg {String} headers Specifies one or more header cells a cell is related to
7383 * @cfg {Number} height Sets the height of a cell
7384 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7385 * @cfg {Number} rowspan Sets the number of rows a cell should span
7386 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7387 * @cfg {String} valign Vertical aligns the content in a cell
7388 * @cfg {Number} width Specifies the width of a cell
7391 * Create a new TableCell
7392 * @param {Object} config The config object
7395 Roo.bootstrap.TableCell = function(config){
7396 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7399 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7419 getAutoCreate : function(){
7420 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7440 cfg.align=this.align
7446 cfg.bgcolor=this.bgcolor
7449 cfg.charoff=this.charoff
7452 cfg.colspan=this.colspan
7455 cfg.headers=this.headers
7458 cfg.height=this.height
7461 cfg.nowrap=this.nowrap
7464 cfg.rowspan=this.rowspan
7467 cfg.scope=this.scope
7470 cfg.valign=this.valign
7473 cfg.width=this.width
7492 * @class Roo.bootstrap.TableRow
7493 * @extends Roo.bootstrap.Component
7494 * Bootstrap TableRow class
7495 * @cfg {String} cls row class
7496 * @cfg {String} align Aligns the content in a table row
7497 * @cfg {String} bgcolor Specifies a background color for a table row
7498 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7499 * @cfg {String} valign Vertical aligns the content in a table row
7502 * Create a new TableRow
7503 * @param {Object} config The config object
7506 Roo.bootstrap.TableRow = function(config){
7507 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7510 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7518 getAutoCreate : function(){
7519 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7529 cfg.align = this.align;
7532 cfg.bgcolor = this.bgcolor;
7535 cfg.charoff = this.charoff;
7538 cfg.valign = this.valign;
7556 * @class Roo.bootstrap.TableBody
7557 * @extends Roo.bootstrap.Component
7558 * Bootstrap TableBody class
7559 * @cfg {String} cls element class
7560 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7561 * @cfg {String} align Aligns the content inside the element
7562 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7563 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7566 * Create a new TableBody
7567 * @param {Object} config The config object
7570 Roo.bootstrap.TableBody = function(config){
7571 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7574 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7582 getAutoCreate : function(){
7583 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7597 cfg.align = this.align;
7600 cfg.charoff = this.charoff;
7603 cfg.valign = this.valign;
7610 // initEvents : function()
7617 // this.store = Roo.factory(this.store, Roo.data);
7618 // this.store.on('load', this.onLoad, this);
7620 // this.store.load();
7624 // onLoad: function ()
7626 // this.fireEvent('load', this);
7636 * Ext JS Library 1.1.1
7637 * Copyright(c) 2006-2007, Ext JS, LLC.
7639 * Originally Released Under LGPL - original licence link has changed is not relivant.
7642 * <script type="text/javascript">
7645 // as we use this in bootstrap.
7646 Roo.namespace('Roo.form');
7648 * @class Roo.form.Action
7649 * Internal Class used to handle form actions
7651 * @param {Roo.form.BasicForm} el The form element or its id
7652 * @param {Object} config Configuration options
7657 // define the action interface
7658 Roo.form.Action = function(form, options){
7660 this.options = options || {};
7663 * Client Validation Failed
7666 Roo.form.Action.CLIENT_INVALID = 'client';
7668 * Server Validation Failed
7671 Roo.form.Action.SERVER_INVALID = 'server';
7673 * Connect to Server Failed
7676 Roo.form.Action.CONNECT_FAILURE = 'connect';
7678 * Reading Data from Server Failed
7681 Roo.form.Action.LOAD_FAILURE = 'load';
7683 Roo.form.Action.prototype = {
7685 failureType : undefined,
7686 response : undefined,
7690 run : function(options){
7695 success : function(response){
7700 handleResponse : function(response){
7704 // default connection failure
7705 failure : function(response){
7707 this.response = response;
7708 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7709 this.form.afterAction(this, false);
7712 processResponse : function(response){
7713 this.response = response;
7714 if(!response.responseText){
7717 this.result = this.handleResponse(response);
7721 // utility functions used internally
7722 getUrl : function(appendParams){
7723 var url = this.options.url || this.form.url || this.form.el.dom.action;
7725 var p = this.getParams();
7727 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7733 getMethod : function(){
7734 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7737 getParams : function(){
7738 var bp = this.form.baseParams;
7739 var p = this.options.params;
7741 if(typeof p == "object"){
7742 p = Roo.urlEncode(Roo.applyIf(p, bp));
7743 }else if(typeof p == 'string' && bp){
7744 p += '&' + Roo.urlEncode(bp);
7747 p = Roo.urlEncode(bp);
7752 createCallback : function(){
7754 success: this.success,
7755 failure: this.failure,
7757 timeout: (this.form.timeout*1000),
7758 upload: this.form.fileUpload ? this.success : undefined
7763 Roo.form.Action.Submit = function(form, options){
7764 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7767 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7770 haveProgress : false,
7771 uploadComplete : false,
7773 // uploadProgress indicator.
7774 uploadProgress : function()
7776 if (!this.form.progressUrl) {
7780 if (!this.haveProgress) {
7781 Roo.MessageBox.progress("Uploading", "Uploading");
7783 if (this.uploadComplete) {
7784 Roo.MessageBox.hide();
7788 this.haveProgress = true;
7790 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7792 var c = new Roo.data.Connection();
7794 url : this.form.progressUrl,
7799 success : function(req){
7800 //console.log(data);
7804 rdata = Roo.decode(req.responseText)
7806 Roo.log("Invalid data from server..");
7810 if (!rdata || !rdata.success) {
7812 Roo.MessageBox.alert(Roo.encode(rdata));
7815 var data = rdata.data;
7817 if (this.uploadComplete) {
7818 Roo.MessageBox.hide();
7823 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7824 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7827 this.uploadProgress.defer(2000,this);
7830 failure: function(data) {
7831 Roo.log('progress url failed ');
7842 // run get Values on the form, so it syncs any secondary forms.
7843 this.form.getValues();
7845 var o = this.options;
7846 var method = this.getMethod();
7847 var isPost = method == 'POST';
7848 if(o.clientValidation === false || this.form.isValid()){
7850 if (this.form.progressUrl) {
7851 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7852 (new Date() * 1) + '' + Math.random());
7857 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7858 form:this.form.el.dom,
7859 url:this.getUrl(!isPost),
7861 params:isPost ? this.getParams() : null,
7862 isUpload: this.form.fileUpload
7865 this.uploadProgress();
7867 }else if (o.clientValidation !== false){ // client validation failed
7868 this.failureType = Roo.form.Action.CLIENT_INVALID;
7869 this.form.afterAction(this, false);
7873 success : function(response)
7875 this.uploadComplete= true;
7876 if (this.haveProgress) {
7877 Roo.MessageBox.hide();
7881 var result = this.processResponse(response);
7882 if(result === true || result.success){
7883 this.form.afterAction(this, true);
7887 this.form.markInvalid(result.errors);
7888 this.failureType = Roo.form.Action.SERVER_INVALID;
7890 this.form.afterAction(this, false);
7892 failure : function(response)
7894 this.uploadComplete= true;
7895 if (this.haveProgress) {
7896 Roo.MessageBox.hide();
7899 this.response = response;
7900 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7901 this.form.afterAction(this, false);
7904 handleResponse : function(response){
7905 if(this.form.errorReader){
7906 var rs = this.form.errorReader.read(response);
7909 for(var i = 0, len = rs.records.length; i < len; i++) {
7910 var r = rs.records[i];
7914 if(errors.length < 1){
7918 success : rs.success,
7924 ret = Roo.decode(response.responseText);
7928 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7938 Roo.form.Action.Load = function(form, options){
7939 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7940 this.reader = this.form.reader;
7943 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7948 Roo.Ajax.request(Roo.apply(
7949 this.createCallback(), {
7950 method:this.getMethod(),
7951 url:this.getUrl(false),
7952 params:this.getParams()
7956 success : function(response){
7958 var result = this.processResponse(response);
7959 if(result === true || !result.success || !result.data){
7960 this.failureType = Roo.form.Action.LOAD_FAILURE;
7961 this.form.afterAction(this, false);
7964 this.form.clearInvalid();
7965 this.form.setValues(result.data);
7966 this.form.afterAction(this, true);
7969 handleResponse : function(response){
7970 if(this.form.reader){
7971 var rs = this.form.reader.read(response);
7972 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7974 success : rs.success,
7978 return Roo.decode(response.responseText);
7982 Roo.form.Action.ACTION_TYPES = {
7983 'load' : Roo.form.Action.Load,
7984 'submit' : Roo.form.Action.Submit
7993 * @class Roo.bootstrap.Form
7994 * @extends Roo.bootstrap.Component
7995 * Bootstrap Form class
7996 * @cfg {String} method GET | POST (default POST)
7997 * @cfg {String} labelAlign top | left (default top)
7998 * @cfg {String} align left | right - for navbars
7999 * @cfg {Boolean} loadMask load mask when submit (default true)
8004 * @param {Object} config The config object
8008 Roo.bootstrap.Form = function(config){
8010 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8012 Roo.bootstrap.Form.popover.apply();
8016 * @event clientvalidation
8017 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8018 * @param {Form} this
8019 * @param {Boolean} valid true if the form has passed client-side validation
8021 clientvalidation: true,
8023 * @event beforeaction
8024 * Fires before any action is performed. Return false to cancel the action.
8025 * @param {Form} this
8026 * @param {Action} action The action to be performed
8030 * @event actionfailed
8031 * Fires when an action fails.
8032 * @param {Form} this
8033 * @param {Action} action The action that failed
8035 actionfailed : true,
8037 * @event actioncomplete
8038 * Fires when an action is completed.
8039 * @param {Form} this
8040 * @param {Action} action The action that completed
8042 actioncomplete : true
8046 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8049 * @cfg {String} method
8050 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8055 * The URL to use for form actions if one isn't supplied in the action options.
8058 * @cfg {Boolean} fileUpload
8059 * Set to true if this form is a file upload.
8063 * @cfg {Object} baseParams
8064 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8068 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8072 * @cfg {Sting} align (left|right) for navbar forms
8077 activeAction : null,
8080 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8081 * element by passing it or its id or mask the form itself by passing in true.
8084 waitMsgTarget : false,
8089 * @cfg {Boolean} errorMask (true|false) default false
8094 * @cfg {Number} maskOffset Default 100
8099 * @cfg {Boolean} maskBody
8103 getAutoCreate : function(){
8107 method : this.method || 'POST',
8108 id : this.id || Roo.id(),
8111 if (this.parent().xtype.match(/^Nav/)) {
8112 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8116 if (this.labelAlign == 'left' ) {
8117 cfg.cls += ' form-horizontal';
8123 initEvents : function()
8125 this.el.on('submit', this.onSubmit, this);
8126 // this was added as random key presses on the form where triggering form submit.
8127 this.el.on('keypress', function(e) {
8128 if (e.getCharCode() != 13) {
8131 // we might need to allow it for textareas.. and some other items.
8132 // check e.getTarget().
8134 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8138 Roo.log("keypress blocked");
8146 onSubmit : function(e){
8151 * Returns true if client-side validation on the form is successful.
8154 isValid : function(){
8155 var items = this.getItems();
8159 items.each(function(f){
8165 Roo.log('invalid field: ' + f.name);
8169 if(!target && f.el.isVisible(true)){
8175 if(this.errorMask && !valid){
8176 Roo.bootstrap.Form.popover.mask(this, target);
8183 * Returns true if any fields in this form have changed since their original load.
8186 isDirty : function(){
8188 var items = this.getItems();
8189 items.each(function(f){
8199 * Performs a predefined action (submit or load) or custom actions you define on this form.
8200 * @param {String} actionName The name of the action type
8201 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8202 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8203 * accept other config options):
8205 Property Type Description
8206 ---------------- --------------- ----------------------------------------------------------------------------------
8207 url String The url for the action (defaults to the form's url)
8208 method String The form method to use (defaults to the form's method, or POST if not defined)
8209 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8210 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8211 validate the form on the client (defaults to false)
8213 * @return {BasicForm} this
8215 doAction : function(action, options){
8216 if(typeof action == 'string'){
8217 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8219 if(this.fireEvent('beforeaction', this, action) !== false){
8220 this.beforeAction(action);
8221 action.run.defer(100, action);
8227 beforeAction : function(action){
8228 var o = action.options;
8233 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8235 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8238 // not really supported yet.. ??
8240 //if(this.waitMsgTarget === true){
8241 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8242 //}else if(this.waitMsgTarget){
8243 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8244 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8246 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8252 afterAction : function(action, success){
8253 this.activeAction = null;
8254 var o = action.options;
8259 Roo.get(document.body).unmask();
8265 //if(this.waitMsgTarget === true){
8266 // this.el.unmask();
8267 //}else if(this.waitMsgTarget){
8268 // this.waitMsgTarget.unmask();
8270 // Roo.MessageBox.updateProgress(1);
8271 // Roo.MessageBox.hide();
8278 Roo.callback(o.success, o.scope, [this, action]);
8279 this.fireEvent('actioncomplete', this, action);
8283 // failure condition..
8284 // we have a scenario where updates need confirming.
8285 // eg. if a locking scenario exists..
8286 // we look for { errors : { needs_confirm : true }} in the response.
8288 (typeof(action.result) != 'undefined') &&
8289 (typeof(action.result.errors) != 'undefined') &&
8290 (typeof(action.result.errors.needs_confirm) != 'undefined')
8293 Roo.log("not supported yet");
8296 Roo.MessageBox.confirm(
8297 "Change requires confirmation",
8298 action.result.errorMsg,
8303 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8313 Roo.callback(o.failure, o.scope, [this, action]);
8314 // show an error message if no failed handler is set..
8315 if (!this.hasListener('actionfailed')) {
8316 Roo.log("need to add dialog support");
8318 Roo.MessageBox.alert("Error",
8319 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8320 action.result.errorMsg :
8321 "Saving Failed, please check your entries or try again"
8326 this.fireEvent('actionfailed', this, action);
8331 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8332 * @param {String} id The value to search for
8335 findField : function(id){
8336 var items = this.getItems();
8337 var field = items.get(id);
8339 items.each(function(f){
8340 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8347 return field || null;
8350 * Mark fields in this form invalid in bulk.
8351 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8352 * @return {BasicForm} this
8354 markInvalid : function(errors){
8355 if(errors instanceof Array){
8356 for(var i = 0, len = errors.length; i < len; i++){
8357 var fieldError = errors[i];
8358 var f = this.findField(fieldError.id);
8360 f.markInvalid(fieldError.msg);
8366 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8367 field.markInvalid(errors[id]);
8371 //Roo.each(this.childForms || [], function (f) {
8372 // f.markInvalid(errors);
8379 * Set values for fields in this form in bulk.
8380 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8381 * @return {BasicForm} this
8383 setValues : function(values){
8384 if(values instanceof Array){ // array of objects
8385 for(var i = 0, len = values.length; i < len; i++){
8387 var f = this.findField(v.id);
8389 f.setValue(v.value);
8390 if(this.trackResetOnLoad){
8391 f.originalValue = f.getValue();
8395 }else{ // object hash
8398 if(typeof values[id] != 'function' && (field = this.findField(id))){
8400 if (field.setFromData &&
8402 field.displayField &&
8403 // combos' with local stores can
8404 // be queried via setValue()
8405 // to set their value..
8406 (field.store && !field.store.isLocal)
8410 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8411 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8412 field.setFromData(sd);
8414 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8416 field.setFromData(values);
8419 field.setValue(values[id]);
8423 if(this.trackResetOnLoad){
8424 field.originalValue = field.getValue();
8430 //Roo.each(this.childForms || [], function (f) {
8431 // f.setValues(values);
8438 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8439 * they are returned as an array.
8440 * @param {Boolean} asString
8443 getValues : function(asString){
8444 //if (this.childForms) {
8445 // copy values from the child forms
8446 // Roo.each(this.childForms, function (f) {
8447 // this.setValues(f.getValues());
8453 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8454 if(asString === true){
8457 return Roo.urlDecode(fs);
8461 * Returns the fields in this form as an object with key/value pairs.
8462 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8465 getFieldValues : function(with_hidden)
8467 var items = this.getItems();
8469 items.each(function(f){
8475 var v = f.getValue();
8477 if (f.inputType =='radio') {
8478 if (typeof(ret[f.getName()]) == 'undefined') {
8479 ret[f.getName()] = ''; // empty..
8482 if (!f.el.dom.checked) {
8490 if(f.xtype == 'MoneyField'){
8491 ret[f.currencyName] = f.getCurrency();
8494 // not sure if this supported any more..
8495 if ((typeof(v) == 'object') && f.getRawValue) {
8496 v = f.getRawValue() ; // dates..
8498 // combo boxes where name != hiddenName...
8499 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8500 ret[f.name] = f.getRawValue();
8502 ret[f.getName()] = v;
8509 * Clears all invalid messages in this form.
8510 * @return {BasicForm} this
8512 clearInvalid : function(){
8513 var items = this.getItems();
8515 items.each(function(f){
8524 * @return {BasicForm} this
8527 var items = this.getItems();
8528 items.each(function(f){
8532 Roo.each(this.childForms || [], function (f) {
8540 getItems : function()
8542 var r=new Roo.util.MixedCollection(false, function(o){
8543 return o.id || (o.id = Roo.id());
8545 var iter = function(el) {
8552 Roo.each(el.items,function(e) {
8561 hideFields : function(items)
8563 Roo.each(items, function(i){
8565 var f = this.findField(i);
8576 showFields : function(items)
8578 Roo.each(items, function(i){
8580 var f = this.findField(i);
8593 Roo.apply(Roo.bootstrap.Form, {
8620 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8621 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8622 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8623 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8626 this.maskEl.top.enableDisplayMode("block");
8627 this.maskEl.left.enableDisplayMode("block");
8628 this.maskEl.bottom.enableDisplayMode("block");
8629 this.maskEl.right.enableDisplayMode("block");
8631 this.toolTip = new Roo.bootstrap.Tooltip({
8632 cls : 'roo-form-error-popover',
8634 'left' : ['r-l', [-2,0], 'right'],
8635 'right' : ['l-r', [2,0], 'left'],
8636 'bottom' : ['tl-bl', [0,2], 'top'],
8637 'top' : [ 'bl-tl', [0,-2], 'bottom']
8641 this.toolTip.render(Roo.get(document.body));
8643 this.toolTip.el.enableDisplayMode("block");
8645 Roo.get(document.body).on('click', function(){
8649 Roo.get(document.body).on('touchstart', function(){
8653 this.isApplied = true
8656 mask : function(form, target)
8660 this.target = target;
8662 if(!this.form.errorMask || !target.el){
8666 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8668 Roo.log(scrollable);
8670 var ot = this.target.el.calcOffsetsTo(scrollable);
8672 var scrollTo = ot[1] - this.form.maskOffset;
8674 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8676 scrollable.scrollTo('top', scrollTo);
8678 var box = this.target.el.getBox();
8680 var zIndex = Roo.bootstrap.Modal.zIndex++;
8683 this.maskEl.top.setStyle('position', 'absolute');
8684 this.maskEl.top.setStyle('z-index', zIndex);
8685 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8686 this.maskEl.top.setLeft(0);
8687 this.maskEl.top.setTop(0);
8688 this.maskEl.top.show();
8690 this.maskEl.left.setStyle('position', 'absolute');
8691 this.maskEl.left.setStyle('z-index', zIndex);
8692 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8693 this.maskEl.left.setLeft(0);
8694 this.maskEl.left.setTop(box.y - this.padding);
8695 this.maskEl.left.show();
8697 this.maskEl.bottom.setStyle('position', 'absolute');
8698 this.maskEl.bottom.setStyle('z-index', zIndex);
8699 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8700 this.maskEl.bottom.setLeft(0);
8701 this.maskEl.bottom.setTop(box.bottom + this.padding);
8702 this.maskEl.bottom.show();
8704 this.maskEl.right.setStyle('position', 'absolute');
8705 this.maskEl.right.setStyle('z-index', zIndex);
8706 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8707 this.maskEl.right.setLeft(box.right + this.padding);
8708 this.maskEl.right.setTop(box.y - this.padding);
8709 this.maskEl.right.show();
8711 this.toolTip.bindEl = this.target.el;
8713 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8715 var tip = this.target.blankText;
8717 if(this.target.getValue() !== '' ) {
8719 if (this.target.invalidText.length) {
8720 tip = this.target.invalidText;
8721 } else if (this.target.regexText.length){
8722 tip = this.target.regexText;
8726 this.toolTip.show(tip);
8728 this.intervalID = window.setInterval(function() {
8729 Roo.bootstrap.Form.popover.unmask();
8732 window.onwheel = function(){ return false;};
8734 (function(){ this.isMasked = true; }).defer(500, this);
8740 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8744 this.maskEl.top.setStyle('position', 'absolute');
8745 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8746 this.maskEl.top.hide();
8748 this.maskEl.left.setStyle('position', 'absolute');
8749 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8750 this.maskEl.left.hide();
8752 this.maskEl.bottom.setStyle('position', 'absolute');
8753 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8754 this.maskEl.bottom.hide();
8756 this.maskEl.right.setStyle('position', 'absolute');
8757 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8758 this.maskEl.right.hide();
8760 this.toolTip.hide();
8762 this.toolTip.el.hide();
8764 window.onwheel = function(){ return true;};
8766 if(this.intervalID){
8767 window.clearInterval(this.intervalID);
8768 this.intervalID = false;
8771 this.isMasked = false;
8781 * Ext JS Library 1.1.1
8782 * Copyright(c) 2006-2007, Ext JS, LLC.
8784 * Originally Released Under LGPL - original licence link has changed is not relivant.
8787 * <script type="text/javascript">
8790 * @class Roo.form.VTypes
8791 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8794 Roo.form.VTypes = function(){
8795 // closure these in so they are only created once.
8796 var alpha = /^[a-zA-Z_]+$/;
8797 var alphanum = /^[a-zA-Z0-9_]+$/;
8798 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8799 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8801 // All these messages and functions are configurable
8804 * The function used to validate email addresses
8805 * @param {String} value The email address
8807 'email' : function(v){
8808 return email.test(v);
8811 * The error text to display when the email validation function returns false
8814 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8816 * The keystroke filter mask to be applied on email input
8819 'emailMask' : /[a-z0-9_\.\-@]/i,
8822 * The function used to validate URLs
8823 * @param {String} value The URL
8825 'url' : function(v){
8829 * The error text to display when the url validation function returns false
8832 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8835 * The function used to validate alpha values
8836 * @param {String} value The value
8838 'alpha' : function(v){
8839 return alpha.test(v);
8842 * The error text to display when the alpha validation function returns false
8845 'alphaText' : 'This field should only contain letters and _',
8847 * The keystroke filter mask to be applied on alpha input
8850 'alphaMask' : /[a-z_]/i,
8853 * The function used to validate alphanumeric values
8854 * @param {String} value The value
8856 'alphanum' : function(v){
8857 return alphanum.test(v);
8860 * The error text to display when the alphanumeric validation function returns false
8863 'alphanumText' : 'This field should only contain letters, numbers and _',
8865 * The keystroke filter mask to be applied on alphanumeric input
8868 'alphanumMask' : /[a-z0-9_]/i
8878 * @class Roo.bootstrap.Input
8879 * @extends Roo.bootstrap.Component
8880 * Bootstrap Input class
8881 * @cfg {Boolean} disabled is it disabled
8882 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8883 * @cfg {String} name name of the input
8884 * @cfg {string} fieldLabel - the label associated
8885 * @cfg {string} placeholder - placeholder to put in text.
8886 * @cfg {string} before - input group add on before
8887 * @cfg {string} after - input group add on after
8888 * @cfg {string} size - (lg|sm) or leave empty..
8889 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8890 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8891 * @cfg {Number} md colspan out of 12 for computer-sized screens
8892 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8893 * @cfg {string} value default value of the input
8894 * @cfg {Number} labelWidth set the width of label
8895 * @cfg {Number} labellg set the width of label (1-12)
8896 * @cfg {Number} labelmd set the width of label (1-12)
8897 * @cfg {Number} labelsm set the width of label (1-12)
8898 * @cfg {Number} labelxs set the width of label (1-12)
8899 * @cfg {String} labelAlign (top|left)
8900 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8901 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8902 * @cfg {String} indicatorpos (left|right) default left
8903 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8904 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8906 * @cfg {String} align (left|center|right) Default left
8907 * @cfg {Boolean} forceFeedback (true|false) Default false
8910 * Create a new Input
8911 * @param {Object} config The config object
8914 Roo.bootstrap.Input = function(config){
8916 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8921 * Fires when this field receives input focus.
8922 * @param {Roo.form.Field} this
8927 * Fires when this field loses input focus.
8928 * @param {Roo.form.Field} this
8933 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8934 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8935 * @param {Roo.form.Field} this
8936 * @param {Roo.EventObject} e The event object
8941 * Fires just before the field blurs if the field value has changed.
8942 * @param {Roo.form.Field} this
8943 * @param {Mixed} newValue The new value
8944 * @param {Mixed} oldValue The original value
8949 * Fires after the field has been marked as invalid.
8950 * @param {Roo.form.Field} this
8951 * @param {String} msg The validation message
8956 * Fires after the field has been validated with no errors.
8957 * @param {Roo.form.Field} this
8962 * Fires after the key up
8963 * @param {Roo.form.Field} this
8964 * @param {Roo.EventObject} e The event Object
8970 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8972 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8973 automatic validation (defaults to "keyup").
8975 validationEvent : "keyup",
8977 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8979 validateOnBlur : true,
8981 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8983 validationDelay : 250,
8985 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8987 focusClass : "x-form-focus", // not needed???
8991 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8993 invalidClass : "has-warning",
8996 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8998 validClass : "has-success",
9001 * @cfg {Boolean} hasFeedback (true|false) default true
9006 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9008 invalidFeedbackClass : "glyphicon-warning-sign",
9011 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9013 validFeedbackClass : "glyphicon-ok",
9016 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9018 selectOnFocus : false,
9021 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9025 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9030 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9032 disableKeyFilter : false,
9035 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9039 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9043 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9045 blankText : "Please complete this mandatory field",
9048 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9052 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9054 maxLength : Number.MAX_VALUE,
9056 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9058 minLengthText : "The minimum length for this field is {0}",
9060 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9062 maxLengthText : "The maximum length for this field is {0}",
9066 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9067 * If available, this function will be called only after the basic validators all return true, and will be passed the
9068 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9072 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9073 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9074 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9078 * @cfg {String} regexText -- Depricated - use Invalid Text
9083 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9089 autocomplete: false,
9108 formatedValue : false,
9109 forceFeedback : false,
9111 indicatorpos : 'left',
9121 parentLabelAlign : function()
9124 while (parent.parent()) {
9125 parent = parent.parent();
9126 if (typeof(parent.labelAlign) !='undefined') {
9127 return parent.labelAlign;
9134 getAutoCreate : function()
9136 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9142 if(this.inputType != 'hidden'){
9143 cfg.cls = 'form-group' //input-group
9149 type : this.inputType,
9151 cls : 'form-control',
9152 placeholder : this.placeholder || '',
9153 autocomplete : this.autocomplete || 'new-password'
9156 if(this.capture.length){
9157 input.capture = this.capture;
9160 if(this.accept.length){
9161 input.accept = this.accept + "/*";
9165 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9168 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9169 input.maxLength = this.maxLength;
9172 if (this.disabled) {
9173 input.disabled=true;
9176 if (this.readOnly) {
9177 input.readonly=true;
9181 input.name = this.name;
9185 input.cls += ' input-' + this.size;
9189 ['xs','sm','md','lg'].map(function(size){
9190 if (settings[size]) {
9191 cfg.cls += ' col-' + size + '-' + settings[size];
9195 var inputblock = input;
9199 cls: 'glyphicon form-control-feedback'
9202 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9205 cls : 'has-feedback',
9213 if (this.before || this.after) {
9216 cls : 'input-group',
9220 if (this.before && typeof(this.before) == 'string') {
9222 inputblock.cn.push({
9224 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9228 if (this.before && typeof(this.before) == 'object') {
9229 this.before = Roo.factory(this.before);
9231 inputblock.cn.push({
9233 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9234 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9238 inputblock.cn.push(input);
9240 if (this.after && typeof(this.after) == 'string') {
9241 inputblock.cn.push({
9243 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9247 if (this.after && typeof(this.after) == 'object') {
9248 this.after = Roo.factory(this.after);
9250 inputblock.cn.push({
9252 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9253 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9257 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9258 inputblock.cls += ' has-feedback';
9259 inputblock.cn.push(feedback);
9264 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9265 tooltip : 'This field is required'
9267 if (Roo.bootstrap.version == 4) {
9270 style : 'display-none'
9273 if (align ==='left' && this.fieldLabel.length) {
9275 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9282 cls : 'control-label col-form-label',
9283 html : this.fieldLabel
9294 var labelCfg = cfg.cn[1];
9295 var contentCfg = cfg.cn[2];
9297 if(this.indicatorpos == 'right'){
9302 cls : 'control-label col-form-label',
9306 html : this.fieldLabel
9320 labelCfg = cfg.cn[0];
9321 contentCfg = cfg.cn[1];
9325 if(this.labelWidth > 12){
9326 labelCfg.style = "width: " + this.labelWidth + 'px';
9329 if(this.labelWidth < 13 && this.labelmd == 0){
9330 this.labelmd = this.labelWidth;
9333 if(this.labellg > 0){
9334 labelCfg.cls += ' col-lg-' + this.labellg;
9335 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9338 if(this.labelmd > 0){
9339 labelCfg.cls += ' col-md-' + this.labelmd;
9340 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9343 if(this.labelsm > 0){
9344 labelCfg.cls += ' col-sm-' + this.labelsm;
9345 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9348 if(this.labelxs > 0){
9349 labelCfg.cls += ' col-xs-' + this.labelxs;
9350 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9354 } else if ( this.fieldLabel.length) {
9359 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9360 tooltip : 'This field is required'
9364 //cls : 'input-group-addon',
9365 html : this.fieldLabel
9373 if(this.indicatorpos == 'right'){
9378 //cls : 'input-group-addon',
9379 html : this.fieldLabel
9384 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9385 tooltip : 'This field is required'
9405 if (this.parentType === 'Navbar' && this.parent().bar) {
9406 cfg.cls += ' navbar-form';
9409 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9410 // on BS4 we do this only if not form
9411 cfg.cls += ' navbar-form';
9419 * return the real input element.
9421 inputEl: function ()
9423 return this.el.select('input.form-control',true).first();
9426 tooltipEl : function()
9428 return this.inputEl();
9431 indicatorEl : function()
9433 if (Roo.bootstrap.version == 4) {
9434 return false; // not enabled in v4 yet.
9437 var indicator = this.el.select('i.roo-required-indicator',true).first();
9447 setDisabled : function(v)
9449 var i = this.inputEl().dom;
9451 i.removeAttribute('disabled');
9455 i.setAttribute('disabled','true');
9457 initEvents : function()
9460 this.inputEl().on("keydown" , this.fireKey, this);
9461 this.inputEl().on("focus", this.onFocus, this);
9462 this.inputEl().on("blur", this.onBlur, this);
9464 this.inputEl().relayEvent('keyup', this);
9466 this.indicator = this.indicatorEl();
9469 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9472 // reference to original value for reset
9473 this.originalValue = this.getValue();
9474 //Roo.form.TextField.superclass.initEvents.call(this);
9475 if(this.validationEvent == 'keyup'){
9476 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9477 this.inputEl().on('keyup', this.filterValidation, this);
9479 else if(this.validationEvent !== false){
9480 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9483 if(this.selectOnFocus){
9484 this.on("focus", this.preFocus, this);
9487 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9488 this.inputEl().on("keypress", this.filterKeys, this);
9490 this.inputEl().relayEvent('keypress', this);
9493 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9494 this.el.on("click", this.autoSize, this);
9497 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9498 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9501 if (typeof(this.before) == 'object') {
9502 this.before.render(this.el.select('.roo-input-before',true).first());
9504 if (typeof(this.after) == 'object') {
9505 this.after.render(this.el.select('.roo-input-after',true).first());
9508 this.inputEl().on('change', this.onChange, this);
9511 filterValidation : function(e){
9512 if(!e.isNavKeyPress()){
9513 this.validationTask.delay(this.validationDelay);
9517 * Validates the field value
9518 * @return {Boolean} True if the value is valid, else false
9520 validate : function(){
9521 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9522 if(this.disabled || this.validateValue(this.getRawValue())){
9533 * Validates a value according to the field's validation rules and marks the field as invalid
9534 * if the validation fails
9535 * @param {Mixed} value The value to validate
9536 * @return {Boolean} True if the value is valid, else false
9538 validateValue : function(value)
9540 if(this.getVisibilityEl().hasClass('hidden')){
9544 if(value.length < 1) { // if it's blank
9545 if(this.allowBlank){
9551 if(value.length < this.minLength){
9554 if(value.length > this.maxLength){
9558 var vt = Roo.form.VTypes;
9559 if(!vt[this.vtype](value, this)){
9563 if(typeof this.validator == "function"){
9564 var msg = this.validator(value);
9568 if (typeof(msg) == 'string') {
9569 this.invalidText = msg;
9573 if(this.regex && !this.regex.test(value)){
9581 fireKey : function(e){
9582 //Roo.log('field ' + e.getKey());
9583 if(e.isNavKeyPress()){
9584 this.fireEvent("specialkey", this, e);
9587 focus : function (selectText){
9589 this.inputEl().focus();
9590 if(selectText === true){
9591 this.inputEl().dom.select();
9597 onFocus : function(){
9598 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9599 // this.el.addClass(this.focusClass);
9602 this.hasFocus = true;
9603 this.startValue = this.getValue();
9604 this.fireEvent("focus", this);
9608 beforeBlur : Roo.emptyFn,
9612 onBlur : function(){
9614 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9615 //this.el.removeClass(this.focusClass);
9617 this.hasFocus = false;
9618 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9621 var v = this.getValue();
9622 if(String(v) !== String(this.startValue)){
9623 this.fireEvent('change', this, v, this.startValue);
9625 this.fireEvent("blur", this);
9628 onChange : function(e)
9630 var v = this.getValue();
9631 if(String(v) !== String(this.startValue)){
9632 this.fireEvent('change', this, v, this.startValue);
9638 * Resets the current field value to the originally loaded value and clears any validation messages
9641 this.setValue(this.originalValue);
9645 * Returns the name of the field
9646 * @return {Mixed} name The name field
9648 getName: function(){
9652 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9653 * @return {Mixed} value The field value
9655 getValue : function(){
9657 var v = this.inputEl().getValue();
9662 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9663 * @return {Mixed} value The field value
9665 getRawValue : function(){
9666 var v = this.inputEl().getValue();
9672 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9673 * @param {Mixed} value The value to set
9675 setRawValue : function(v){
9676 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9679 selectText : function(start, end){
9680 var v = this.getRawValue();
9682 start = start === undefined ? 0 : start;
9683 end = end === undefined ? v.length : end;
9684 var d = this.inputEl().dom;
9685 if(d.setSelectionRange){
9686 d.setSelectionRange(start, end);
9687 }else if(d.createTextRange){
9688 var range = d.createTextRange();
9689 range.moveStart("character", start);
9690 range.moveEnd("character", v.length-end);
9697 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9698 * @param {Mixed} value The value to set
9700 setValue : function(v){
9703 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9709 processValue : function(value){
9710 if(this.stripCharsRe){
9711 var newValue = value.replace(this.stripCharsRe, '');
9712 if(newValue !== value){
9713 this.setRawValue(newValue);
9720 preFocus : function(){
9722 if(this.selectOnFocus){
9723 this.inputEl().dom.select();
9726 filterKeys : function(e){
9728 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9731 var c = e.getCharCode(), cc = String.fromCharCode(c);
9732 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9735 if(!this.maskRe.test(cc)){
9740 * Clear any invalid styles/messages for this field
9742 clearInvalid : function(){
9744 if(!this.el || this.preventMark){ // not rendered
9749 this.el.removeClass(this.invalidClass);
9751 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9753 var feedback = this.el.select('.form-control-feedback', true).first();
9756 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9762 this.indicator.removeClass('visible');
9763 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9766 this.fireEvent('valid', this);
9770 * Mark this field as valid
9772 markValid : function()
9774 if(!this.el || this.preventMark){ // not rendered...
9778 this.el.removeClass([this.invalidClass, this.validClass]);
9780 var feedback = this.el.select('.form-control-feedback', true).first();
9783 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9787 this.indicator.removeClass('visible');
9788 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9795 if(this.allowBlank && !this.getRawValue().length){
9799 this.el.addClass(this.validClass);
9801 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9803 var feedback = this.el.select('.form-control-feedback', true).first();
9806 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9807 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9812 this.fireEvent('valid', this);
9816 * Mark this field as invalid
9817 * @param {String} msg The validation message
9819 markInvalid : function(msg)
9821 if(!this.el || this.preventMark){ // not rendered
9825 this.el.removeClass([this.invalidClass, this.validClass]);
9827 var feedback = this.el.select('.form-control-feedback', true).first();
9830 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9837 if(this.allowBlank && !this.getRawValue().length){
9842 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9843 this.indicator.addClass('visible');
9846 this.el.addClass(this.invalidClass);
9848 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9850 var feedback = this.el.select('.form-control-feedback', true).first();
9853 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9855 if(this.getValue().length || this.forceFeedback){
9856 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9863 this.fireEvent('invalid', this, msg);
9866 SafariOnKeyDown : function(event)
9868 // this is a workaround for a password hang bug on chrome/ webkit.
9869 if (this.inputEl().dom.type != 'password') {
9873 var isSelectAll = false;
9875 if(this.inputEl().dom.selectionEnd > 0){
9876 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9878 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9879 event.preventDefault();
9884 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9886 event.preventDefault();
9887 // this is very hacky as keydown always get's upper case.
9889 var cc = String.fromCharCode(event.getCharCode());
9890 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9894 adjustWidth : function(tag, w){
9895 tag = tag.toLowerCase();
9896 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9897 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9901 if(tag == 'textarea'){
9904 }else if(Roo.isOpera){
9908 if(tag == 'textarea'){
9916 setFieldLabel : function(v)
9922 if(this.indicatorEl()){
9923 var ar = this.el.select('label > span',true);
9925 if (ar.elements.length) {
9926 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9927 this.fieldLabel = v;
9931 var br = this.el.select('label',true);
9933 if(br.elements.length) {
9934 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9935 this.fieldLabel = v;
9939 Roo.log('Cannot Found any of label > span || label in input');
9943 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9944 this.fieldLabel = v;
9959 * @class Roo.bootstrap.TextArea
9960 * @extends Roo.bootstrap.Input
9961 * Bootstrap TextArea class
9962 * @cfg {Number} cols Specifies the visible width of a text area
9963 * @cfg {Number} rows Specifies the visible number of lines in a text area
9964 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9965 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9966 * @cfg {string} html text
9969 * Create a new TextArea
9970 * @param {Object} config The config object
9973 Roo.bootstrap.TextArea = function(config){
9974 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9978 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9988 getAutoCreate : function(){
9990 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9996 if(this.inputType != 'hidden'){
9997 cfg.cls = 'form-group' //input-group
10005 value : this.value || '',
10006 html: this.html || '',
10007 cls : 'form-control',
10008 placeholder : this.placeholder || ''
10012 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10013 input.maxLength = this.maxLength;
10017 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10021 input.cols = this.cols;
10024 if (this.readOnly) {
10025 input.readonly = true;
10029 input.name = this.name;
10033 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10037 ['xs','sm','md','lg'].map(function(size){
10038 if (settings[size]) {
10039 cfg.cls += ' col-' + size + '-' + settings[size];
10043 var inputblock = input;
10045 if(this.hasFeedback && !this.allowBlank){
10049 cls: 'glyphicon form-control-feedback'
10053 cls : 'has-feedback',
10062 if (this.before || this.after) {
10065 cls : 'input-group',
10069 inputblock.cn.push({
10071 cls : 'input-group-addon',
10076 inputblock.cn.push(input);
10078 if(this.hasFeedback && !this.allowBlank){
10079 inputblock.cls += ' has-feedback';
10080 inputblock.cn.push(feedback);
10084 inputblock.cn.push({
10086 cls : 'input-group-addon',
10093 if (align ==='left' && this.fieldLabel.length) {
10098 cls : 'control-label',
10099 html : this.fieldLabel
10110 if(this.labelWidth > 12){
10111 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10114 if(this.labelWidth < 13 && this.labelmd == 0){
10115 this.labelmd = this.labelWidth;
10118 if(this.labellg > 0){
10119 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10120 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10123 if(this.labelmd > 0){
10124 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10125 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10128 if(this.labelsm > 0){
10129 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10130 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10133 if(this.labelxs > 0){
10134 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10135 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10138 } else if ( this.fieldLabel.length) {
10143 //cls : 'input-group-addon',
10144 html : this.fieldLabel
10162 if (this.disabled) {
10163 input.disabled=true;
10170 * return the real textarea element.
10172 inputEl: function ()
10174 return this.el.select('textarea.form-control',true).first();
10178 * Clear any invalid styles/messages for this field
10180 clearInvalid : function()
10183 if(!this.el || this.preventMark){ // not rendered
10187 var label = this.el.select('label', true).first();
10188 var icon = this.el.select('i.fa-star', true).first();
10194 this.el.removeClass(this.invalidClass);
10196 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10198 var feedback = this.el.select('.form-control-feedback', true).first();
10201 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10206 this.fireEvent('valid', this);
10210 * Mark this field as valid
10212 markValid : function()
10214 if(!this.el || this.preventMark){ // not rendered
10218 this.el.removeClass([this.invalidClass, this.validClass]);
10220 var feedback = this.el.select('.form-control-feedback', true).first();
10223 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10226 if(this.disabled || this.allowBlank){
10230 var label = this.el.select('label', true).first();
10231 var icon = this.el.select('i.fa-star', true).first();
10237 this.el.addClass(this.validClass);
10239 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10241 var feedback = this.el.select('.form-control-feedback', true).first();
10244 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10245 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10250 this.fireEvent('valid', this);
10254 * Mark this field as invalid
10255 * @param {String} msg The validation message
10257 markInvalid : function(msg)
10259 if(!this.el || this.preventMark){ // not rendered
10263 this.el.removeClass([this.invalidClass, this.validClass]);
10265 var feedback = this.el.select('.form-control-feedback', true).first();
10268 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10271 if(this.disabled || this.allowBlank){
10275 var label = this.el.select('label', true).first();
10276 var icon = this.el.select('i.fa-star', true).first();
10278 if(!this.getValue().length && label && !icon){
10279 this.el.createChild({
10281 cls : 'text-danger fa fa-lg fa-star',
10282 tooltip : 'This field is required',
10283 style : 'margin-right:5px;'
10287 this.el.addClass(this.invalidClass);
10289 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10291 var feedback = this.el.select('.form-control-feedback', true).first();
10294 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10296 if(this.getValue().length || this.forceFeedback){
10297 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10304 this.fireEvent('invalid', this, msg);
10312 * trigger field - base class for combo..
10317 * @class Roo.bootstrap.TriggerField
10318 * @extends Roo.bootstrap.Input
10319 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10320 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10321 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10322 * for which you can provide a custom implementation. For example:
10324 var trigger = new Roo.bootstrap.TriggerField();
10325 trigger.onTriggerClick = myTriggerFn;
10326 trigger.applyTo('my-field');
10329 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10330 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10331 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10332 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10333 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10336 * Create a new TriggerField.
10337 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10338 * to the base TextField)
10340 Roo.bootstrap.TriggerField = function(config){
10341 this.mimicing = false;
10342 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10345 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10347 * @cfg {String} triggerClass A CSS class to apply to the trigger
10350 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10355 * @cfg {Boolean} removable (true|false) special filter default false
10359 /** @cfg {Boolean} grow @hide */
10360 /** @cfg {Number} growMin @hide */
10361 /** @cfg {Number} growMax @hide */
10367 autoSize: Roo.emptyFn,
10371 deferHeight : true,
10374 actionMode : 'wrap',
10379 getAutoCreate : function(){
10381 var align = this.labelAlign || this.parentLabelAlign();
10386 cls: 'form-group' //input-group
10393 type : this.inputType,
10394 cls : 'form-control',
10395 autocomplete: 'new-password',
10396 placeholder : this.placeholder || ''
10400 input.name = this.name;
10403 input.cls += ' input-' + this.size;
10406 if (this.disabled) {
10407 input.disabled=true;
10410 var inputblock = input;
10412 if(this.hasFeedback && !this.allowBlank){
10416 cls: 'glyphicon form-control-feedback'
10419 if(this.removable && !this.editable && !this.tickable){
10421 cls : 'has-feedback',
10427 cls : 'roo-combo-removable-btn close'
10434 cls : 'has-feedback',
10443 if(this.removable && !this.editable && !this.tickable){
10445 cls : 'roo-removable',
10451 cls : 'roo-combo-removable-btn close'
10458 if (this.before || this.after) {
10461 cls : 'input-group',
10465 inputblock.cn.push({
10467 cls : 'input-group-addon input-group-prepend input-group-text',
10472 inputblock.cn.push(input);
10474 if(this.hasFeedback && !this.allowBlank){
10475 inputblock.cls += ' has-feedback';
10476 inputblock.cn.push(feedback);
10480 inputblock.cn.push({
10482 cls : 'input-group-addon input-group-append input-group-text',
10491 var ibwrap = inputblock;
10496 cls: 'roo-select2-choices',
10500 cls: 'roo-select2-search-field',
10512 cls: 'roo-select2-container input-group',
10517 cls: 'form-hidden-field'
10523 if(!this.multiple && this.showToggleBtn){
10529 if (this.caret != false) {
10532 cls: 'fa fa-' + this.caret
10539 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10544 cls: 'combobox-clear',
10558 combobox.cls += ' roo-select2-container-multi';
10562 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10563 tooltip : 'This field is required'
10565 if (Roo.bootstrap.version == 4) {
10568 style : 'display:none'
10573 if (align ==='left' && this.fieldLabel.length) {
10575 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10582 cls : 'control-label',
10583 html : this.fieldLabel
10595 var labelCfg = cfg.cn[1];
10596 var contentCfg = cfg.cn[2];
10598 if(this.indicatorpos == 'right'){
10603 cls : 'control-label',
10607 html : this.fieldLabel
10621 labelCfg = cfg.cn[0];
10622 contentCfg = cfg.cn[1];
10625 if(this.labelWidth > 12){
10626 labelCfg.style = "width: " + this.labelWidth + 'px';
10629 if(this.labelWidth < 13 && this.labelmd == 0){
10630 this.labelmd = this.labelWidth;
10633 if(this.labellg > 0){
10634 labelCfg.cls += ' col-lg-' + this.labellg;
10635 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10638 if(this.labelmd > 0){
10639 labelCfg.cls += ' col-md-' + this.labelmd;
10640 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10643 if(this.labelsm > 0){
10644 labelCfg.cls += ' col-sm-' + this.labelsm;
10645 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10648 if(this.labelxs > 0){
10649 labelCfg.cls += ' col-xs-' + this.labelxs;
10650 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10653 } else if ( this.fieldLabel.length) {
10654 // Roo.log(" label");
10659 //cls : 'input-group-addon',
10660 html : this.fieldLabel
10668 if(this.indicatorpos == 'right'){
10676 html : this.fieldLabel
10690 // Roo.log(" no label && no align");
10697 ['xs','sm','md','lg'].map(function(size){
10698 if (settings[size]) {
10699 cfg.cls += ' col-' + size + '-' + settings[size];
10710 onResize : function(w, h){
10711 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10712 // if(typeof w == 'number'){
10713 // var x = w - this.trigger.getWidth();
10714 // this.inputEl().setWidth(this.adjustWidth('input', x));
10715 // this.trigger.setStyle('left', x+'px');
10720 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10723 getResizeEl : function(){
10724 return this.inputEl();
10728 getPositionEl : function(){
10729 return this.inputEl();
10733 alignErrorIcon : function(){
10734 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10738 initEvents : function(){
10742 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10743 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10744 if(!this.multiple && this.showToggleBtn){
10745 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10746 if(this.hideTrigger){
10747 this.trigger.setDisplayed(false);
10749 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10753 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10756 if(this.removable && !this.editable && !this.tickable){
10757 var close = this.closeTriggerEl();
10760 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10761 close.on('click', this.removeBtnClick, this, close);
10765 //this.trigger.addClassOnOver('x-form-trigger-over');
10766 //this.trigger.addClassOnClick('x-form-trigger-click');
10769 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10773 closeTriggerEl : function()
10775 var close = this.el.select('.roo-combo-removable-btn', true).first();
10776 return close ? close : false;
10779 removeBtnClick : function(e, h, el)
10781 e.preventDefault();
10783 if(this.fireEvent("remove", this) !== false){
10785 this.fireEvent("afterremove", this)
10789 createList : function()
10791 this.list = Roo.get(document.body).createChild({
10792 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10793 cls: 'typeahead typeahead-long dropdown-menu',
10794 style: 'display:none'
10797 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10802 initTrigger : function(){
10807 onDestroy : function(){
10809 this.trigger.removeAllListeners();
10810 // this.trigger.remove();
10813 // this.wrap.remove();
10815 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10819 onFocus : function(){
10820 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10822 if(!this.mimicing){
10823 this.wrap.addClass('x-trigger-wrap-focus');
10824 this.mimicing = true;
10825 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10826 if(this.monitorTab){
10827 this.el.on("keydown", this.checkTab, this);
10834 checkTab : function(e){
10835 if(e.getKey() == e.TAB){
10836 this.triggerBlur();
10841 onBlur : function(){
10846 mimicBlur : function(e, t){
10848 if(!this.wrap.contains(t) && this.validateBlur()){
10849 this.triggerBlur();
10855 triggerBlur : function(){
10856 this.mimicing = false;
10857 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10858 if(this.monitorTab){
10859 this.el.un("keydown", this.checkTab, this);
10861 //this.wrap.removeClass('x-trigger-wrap-focus');
10862 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10866 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10867 validateBlur : function(e, t){
10872 onDisable : function(){
10873 this.inputEl().dom.disabled = true;
10874 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10876 // this.wrap.addClass('x-item-disabled');
10881 onEnable : function(){
10882 this.inputEl().dom.disabled = false;
10883 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10885 // this.el.removeClass('x-item-disabled');
10890 onShow : function(){
10891 var ae = this.getActionEl();
10894 ae.dom.style.display = '';
10895 ae.dom.style.visibility = 'visible';
10901 onHide : function(){
10902 var ae = this.getActionEl();
10903 ae.dom.style.display = 'none';
10907 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10908 * by an implementing function.
10910 * @param {EventObject} e
10912 onTriggerClick : Roo.emptyFn
10916 * Ext JS Library 1.1.1
10917 * Copyright(c) 2006-2007, Ext JS, LLC.
10919 * Originally Released Under LGPL - original licence link has changed is not relivant.
10922 * <script type="text/javascript">
10927 * @class Roo.data.SortTypes
10929 * Defines the default sorting (casting?) comparison functions used when sorting data.
10931 Roo.data.SortTypes = {
10933 * Default sort that does nothing
10934 * @param {Mixed} s The value being converted
10935 * @return {Mixed} The comparison value
10937 none : function(s){
10942 * The regular expression used to strip tags
10946 stripTagsRE : /<\/?[^>]+>/gi,
10949 * Strips all HTML tags to sort on text only
10950 * @param {Mixed} s The value being converted
10951 * @return {String} The comparison value
10953 asText : function(s){
10954 return String(s).replace(this.stripTagsRE, "");
10958 * Strips all HTML tags to sort on text only - Case insensitive
10959 * @param {Mixed} s The value being converted
10960 * @return {String} The comparison value
10962 asUCText : function(s){
10963 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10967 * Case insensitive string
10968 * @param {Mixed} s The value being converted
10969 * @return {String} The comparison value
10971 asUCString : function(s) {
10972 return String(s).toUpperCase();
10977 * @param {Mixed} s The value being converted
10978 * @return {Number} The comparison value
10980 asDate : function(s) {
10984 if(s instanceof Date){
10985 return s.getTime();
10987 return Date.parse(String(s));
10992 * @param {Mixed} s The value being converted
10993 * @return {Float} The comparison value
10995 asFloat : function(s) {
10996 var val = parseFloat(String(s).replace(/,/g, ""));
11005 * @param {Mixed} s The value being converted
11006 * @return {Number} The comparison value
11008 asInt : function(s) {
11009 var val = parseInt(String(s).replace(/,/g, ""));
11017 * Ext JS Library 1.1.1
11018 * Copyright(c) 2006-2007, Ext JS, LLC.
11020 * Originally Released Under LGPL - original licence link has changed is not relivant.
11023 * <script type="text/javascript">
11027 * @class Roo.data.Record
11028 * Instances of this class encapsulate both record <em>definition</em> information, and record
11029 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11030 * to access Records cached in an {@link Roo.data.Store} object.<br>
11032 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11033 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11036 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11038 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11039 * {@link #create}. The parameters are the same.
11040 * @param {Array} data An associative Array of data values keyed by the field name.
11041 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11042 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11043 * not specified an integer id is generated.
11045 Roo.data.Record = function(data, id){
11046 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11051 * Generate a constructor for a specific record layout.
11052 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11053 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11054 * Each field definition object may contain the following properties: <ul>
11055 * <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,
11056 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11057 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11058 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11059 * is being used, then this is a string containing the javascript expression to reference the data relative to
11060 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11061 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11062 * this may be omitted.</p></li>
11063 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11064 * <ul><li>auto (Default, implies no conversion)</li>
11069 * <li>date</li></ul></p></li>
11070 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11071 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11072 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11073 * by the Reader into an object that will be stored in the Record. It is passed the
11074 * following parameters:<ul>
11075 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11077 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11079 * <br>usage:<br><pre><code>
11080 var TopicRecord = Roo.data.Record.create(
11081 {name: 'title', mapping: 'topic_title'},
11082 {name: 'author', mapping: 'username'},
11083 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11084 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11085 {name: 'lastPoster', mapping: 'user2'},
11086 {name: 'excerpt', mapping: 'post_text'}
11089 var myNewRecord = new TopicRecord({
11090 title: 'Do my job please',
11093 lastPost: new Date(),
11094 lastPoster: 'Animal',
11095 excerpt: 'No way dude!'
11097 myStore.add(myNewRecord);
11102 Roo.data.Record.create = function(o){
11103 var f = function(){
11104 f.superclass.constructor.apply(this, arguments);
11106 Roo.extend(f, Roo.data.Record);
11107 var p = f.prototype;
11108 p.fields = new Roo.util.MixedCollection(false, function(field){
11111 for(var i = 0, len = o.length; i < len; i++){
11112 p.fields.add(new Roo.data.Field(o[i]));
11114 f.getField = function(name){
11115 return p.fields.get(name);
11120 Roo.data.Record.AUTO_ID = 1000;
11121 Roo.data.Record.EDIT = 'edit';
11122 Roo.data.Record.REJECT = 'reject';
11123 Roo.data.Record.COMMIT = 'commit';
11125 Roo.data.Record.prototype = {
11127 * Readonly flag - true if this record has been modified.
11136 join : function(store){
11137 this.store = store;
11141 * Set the named field to the specified value.
11142 * @param {String} name The name of the field to set.
11143 * @param {Object} value The value to set the field to.
11145 set : function(name, value){
11146 if(this.data[name] == value){
11150 if(!this.modified){
11151 this.modified = {};
11153 if(typeof this.modified[name] == 'undefined'){
11154 this.modified[name] = this.data[name];
11156 this.data[name] = value;
11157 if(!this.editing && this.store){
11158 this.store.afterEdit(this);
11163 * Get the value of the named field.
11164 * @param {String} name The name of the field to get the value of.
11165 * @return {Object} The value of the field.
11167 get : function(name){
11168 return this.data[name];
11172 beginEdit : function(){
11173 this.editing = true;
11174 this.modified = {};
11178 cancelEdit : function(){
11179 this.editing = false;
11180 delete this.modified;
11184 endEdit : function(){
11185 this.editing = false;
11186 if(this.dirty && this.store){
11187 this.store.afterEdit(this);
11192 * Usually called by the {@link Roo.data.Store} which owns the Record.
11193 * Rejects all changes made to the Record since either creation, or the last commit operation.
11194 * Modified fields are reverted to their original values.
11196 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11197 * of reject operations.
11199 reject : function(){
11200 var m = this.modified;
11202 if(typeof m[n] != "function"){
11203 this.data[n] = m[n];
11206 this.dirty = false;
11207 delete this.modified;
11208 this.editing = false;
11210 this.store.afterReject(this);
11215 * Usually called by the {@link Roo.data.Store} which owns the Record.
11216 * Commits all changes made to the Record since either creation, or the last commit operation.
11218 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11219 * of commit operations.
11221 commit : function(){
11222 this.dirty = false;
11223 delete this.modified;
11224 this.editing = false;
11226 this.store.afterCommit(this);
11231 hasError : function(){
11232 return this.error != null;
11236 clearError : function(){
11241 * Creates a copy of this record.
11242 * @param {String} id (optional) A new record id if you don't want to use this record's id
11245 copy : function(newId) {
11246 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11250 * Ext JS Library 1.1.1
11251 * Copyright(c) 2006-2007, Ext JS, LLC.
11253 * Originally Released Under LGPL - original licence link has changed is not relivant.
11256 * <script type="text/javascript">
11262 * @class Roo.data.Store
11263 * @extends Roo.util.Observable
11264 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11265 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11267 * 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
11268 * has no knowledge of the format of the data returned by the Proxy.<br>
11270 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11271 * instances from the data object. These records are cached and made available through accessor functions.
11273 * Creates a new Store.
11274 * @param {Object} config A config object containing the objects needed for the Store to access data,
11275 * and read the data into Records.
11277 Roo.data.Store = function(config){
11278 this.data = new Roo.util.MixedCollection(false);
11279 this.data.getKey = function(o){
11282 this.baseParams = {};
11284 this.paramNames = {
11289 "multisort" : "_multisort"
11292 if(config && config.data){
11293 this.inlineData = config.data;
11294 delete config.data;
11297 Roo.apply(this, config);
11299 if(this.reader){ // reader passed
11300 this.reader = Roo.factory(this.reader, Roo.data);
11301 this.reader.xmodule = this.xmodule || false;
11302 if(!this.recordType){
11303 this.recordType = this.reader.recordType;
11305 if(this.reader.onMetaChange){
11306 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11310 if(this.recordType){
11311 this.fields = this.recordType.prototype.fields;
11313 this.modified = [];
11317 * @event datachanged
11318 * Fires when the data cache has changed, and a widget which is using this Store
11319 * as a Record cache should refresh its view.
11320 * @param {Store} this
11322 datachanged : true,
11324 * @event metachange
11325 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11326 * @param {Store} this
11327 * @param {Object} meta The JSON metadata
11332 * Fires when Records have been added to the Store
11333 * @param {Store} this
11334 * @param {Roo.data.Record[]} records The array of Records added
11335 * @param {Number} index The index at which the record(s) were added
11340 * Fires when a Record has been removed from the Store
11341 * @param {Store} this
11342 * @param {Roo.data.Record} record The Record that was removed
11343 * @param {Number} index The index at which the record was removed
11348 * Fires when a Record has been updated
11349 * @param {Store} this
11350 * @param {Roo.data.Record} record The Record that was updated
11351 * @param {String} operation The update operation being performed. Value may be one of:
11353 Roo.data.Record.EDIT
11354 Roo.data.Record.REJECT
11355 Roo.data.Record.COMMIT
11361 * Fires when the data cache has been cleared.
11362 * @param {Store} this
11366 * @event beforeload
11367 * Fires before a request is made for a new data object. If the beforeload handler returns false
11368 * the load action will be canceled.
11369 * @param {Store} this
11370 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11374 * @event beforeloadadd
11375 * Fires after a new set of Records has been loaded.
11376 * @param {Store} this
11377 * @param {Roo.data.Record[]} records The Records that were loaded
11378 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11380 beforeloadadd : true,
11383 * Fires after a new set of Records has been loaded, before they are added to the store.
11384 * @param {Store} this
11385 * @param {Roo.data.Record[]} records The Records that were loaded
11386 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11387 * @params {Object} return from reader
11391 * @event loadexception
11392 * Fires if an exception occurs in the Proxy during loading.
11393 * Called with the signature of the Proxy's "loadexception" event.
11394 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11397 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11398 * @param {Object} load options
11399 * @param {Object} jsonData from your request (normally this contains the Exception)
11401 loadexception : true
11405 this.proxy = Roo.factory(this.proxy, Roo.data);
11406 this.proxy.xmodule = this.xmodule || false;
11407 this.relayEvents(this.proxy, ["loadexception"]);
11409 this.sortToggle = {};
11410 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11412 Roo.data.Store.superclass.constructor.call(this);
11414 if(this.inlineData){
11415 this.loadData(this.inlineData);
11416 delete this.inlineData;
11420 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11422 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11423 * without a remote query - used by combo/forms at present.
11427 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11430 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11433 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11434 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11437 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11438 * on any HTTP request
11441 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11444 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11448 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11449 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11451 remoteSort : false,
11454 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11455 * loaded or when a record is removed. (defaults to false).
11457 pruneModifiedRecords : false,
11460 lastOptions : null,
11463 * Add Records to the Store and fires the add event.
11464 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11466 add : function(records){
11467 records = [].concat(records);
11468 for(var i = 0, len = records.length; i < len; i++){
11469 records[i].join(this);
11471 var index = this.data.length;
11472 this.data.addAll(records);
11473 this.fireEvent("add", this, records, index);
11477 * Remove a Record from the Store and fires the remove event.
11478 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11480 remove : function(record){
11481 var index = this.data.indexOf(record);
11482 this.data.removeAt(index);
11484 if(this.pruneModifiedRecords){
11485 this.modified.remove(record);
11487 this.fireEvent("remove", this, record, index);
11491 * Remove all Records from the Store and fires the clear event.
11493 removeAll : function(){
11495 if(this.pruneModifiedRecords){
11496 this.modified = [];
11498 this.fireEvent("clear", this);
11502 * Inserts Records to the Store at the given index and fires the add event.
11503 * @param {Number} index The start index at which to insert the passed Records.
11504 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11506 insert : function(index, records){
11507 records = [].concat(records);
11508 for(var i = 0, len = records.length; i < len; i++){
11509 this.data.insert(index, records[i]);
11510 records[i].join(this);
11512 this.fireEvent("add", this, records, index);
11516 * Get the index within the cache of the passed Record.
11517 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11518 * @return {Number} The index of the passed Record. Returns -1 if not found.
11520 indexOf : function(record){
11521 return this.data.indexOf(record);
11525 * Get the index within the cache of the Record with the passed id.
11526 * @param {String} id The id of the Record to find.
11527 * @return {Number} The index of the Record. Returns -1 if not found.
11529 indexOfId : function(id){
11530 return this.data.indexOfKey(id);
11534 * Get the Record with the specified id.
11535 * @param {String} id The id of the Record to find.
11536 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11538 getById : function(id){
11539 return this.data.key(id);
11543 * Get the Record at the specified index.
11544 * @param {Number} index The index of the Record to find.
11545 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11547 getAt : function(index){
11548 return this.data.itemAt(index);
11552 * Returns a range of Records between specified indices.
11553 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11554 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11555 * @return {Roo.data.Record[]} An array of Records
11557 getRange : function(start, end){
11558 return this.data.getRange(start, end);
11562 storeOptions : function(o){
11563 o = Roo.apply({}, o);
11566 this.lastOptions = o;
11570 * Loads the Record cache from the configured Proxy using the configured Reader.
11572 * If using remote paging, then the first load call must specify the <em>start</em>
11573 * and <em>limit</em> properties in the options.params property to establish the initial
11574 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11576 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11577 * and this call will return before the new data has been loaded. Perform any post-processing
11578 * in a callback function, or in a "load" event handler.</strong>
11580 * @param {Object} options An object containing properties which control loading options:<ul>
11581 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11582 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11583 * passed the following arguments:<ul>
11584 * <li>r : Roo.data.Record[]</li>
11585 * <li>options: Options object from the load call</li>
11586 * <li>success: Boolean success indicator</li></ul></li>
11587 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11588 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11591 load : function(options){
11592 options = options || {};
11593 if(this.fireEvent("beforeload", this, options) !== false){
11594 this.storeOptions(options);
11595 var p = Roo.apply(options.params || {}, this.baseParams);
11596 // if meta was not loaded from remote source.. try requesting it.
11597 if (!this.reader.metaFromRemote) {
11598 p._requestMeta = 1;
11600 if(this.sortInfo && this.remoteSort){
11601 var pn = this.paramNames;
11602 p[pn["sort"]] = this.sortInfo.field;
11603 p[pn["dir"]] = this.sortInfo.direction;
11605 if (this.multiSort) {
11606 var pn = this.paramNames;
11607 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11610 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11615 * Reloads the Record cache from the configured Proxy using the configured Reader and
11616 * the options from the last load operation performed.
11617 * @param {Object} options (optional) An object containing properties which may override the options
11618 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11619 * the most recently used options are reused).
11621 reload : function(options){
11622 this.load(Roo.applyIf(options||{}, this.lastOptions));
11626 // Called as a callback by the Reader during a load operation.
11627 loadRecords : function(o, options, success){
11628 if(!o || success === false){
11629 if(success !== false){
11630 this.fireEvent("load", this, [], options, o);
11632 if(options.callback){
11633 options.callback.call(options.scope || this, [], options, false);
11637 // if data returned failure - throw an exception.
11638 if (o.success === false) {
11639 // show a message if no listener is registered.
11640 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11641 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11643 // loadmask wil be hooked into this..
11644 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11647 var r = o.records, t = o.totalRecords || r.length;
11649 this.fireEvent("beforeloadadd", this, r, options, o);
11651 if(!options || options.add !== true){
11652 if(this.pruneModifiedRecords){
11653 this.modified = [];
11655 for(var i = 0, len = r.length; i < len; i++){
11659 this.data = this.snapshot;
11660 delete this.snapshot;
11663 this.data.addAll(r);
11664 this.totalLength = t;
11666 this.fireEvent("datachanged", this);
11668 this.totalLength = Math.max(t, this.data.length+r.length);
11672 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11674 var e = new Roo.data.Record({});
11676 e.set(this.parent.displayField, this.parent.emptyTitle);
11677 e.set(this.parent.valueField, '');
11682 this.fireEvent("load", this, r, options, o);
11683 if(options.callback){
11684 options.callback.call(options.scope || this, r, options, true);
11690 * Loads data from a passed data block. A Reader which understands the format of the data
11691 * must have been configured in the constructor.
11692 * @param {Object} data The data block from which to read the Records. The format of the data expected
11693 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11694 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11696 loadData : function(o, append){
11697 var r = this.reader.readRecords(o);
11698 this.loadRecords(r, {add: append}, true);
11702 * Gets the number of cached records.
11704 * <em>If using paging, this may not be the total size of the dataset. If the data object
11705 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11706 * the data set size</em>
11708 getCount : function(){
11709 return this.data.length || 0;
11713 * Gets the total number of records in the dataset as returned by the server.
11715 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11716 * the dataset size</em>
11718 getTotalCount : function(){
11719 return this.totalLength || 0;
11723 * Returns the sort state of the Store as an object with two properties:
11725 field {String} The name of the field by which the Records are sorted
11726 direction {String} The sort order, "ASC" or "DESC"
11729 getSortState : function(){
11730 return this.sortInfo;
11734 applySort : function(){
11735 if(this.sortInfo && !this.remoteSort){
11736 var s = this.sortInfo, f = s.field;
11737 var st = this.fields.get(f).sortType;
11738 var fn = function(r1, r2){
11739 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11740 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11742 this.data.sort(s.direction, fn);
11743 if(this.snapshot && this.snapshot != this.data){
11744 this.snapshot.sort(s.direction, fn);
11750 * Sets the default sort column and order to be used by the next load operation.
11751 * @param {String} fieldName The name of the field to sort by.
11752 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11754 setDefaultSort : function(field, dir){
11755 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11759 * Sort the Records.
11760 * If remote sorting is used, the sort is performed on the server, and the cache is
11761 * reloaded. If local sorting is used, the cache is sorted internally.
11762 * @param {String} fieldName The name of the field to sort by.
11763 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11765 sort : function(fieldName, dir){
11766 var f = this.fields.get(fieldName);
11768 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11770 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11771 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11776 this.sortToggle[f.name] = dir;
11777 this.sortInfo = {field: f.name, direction: dir};
11778 if(!this.remoteSort){
11780 this.fireEvent("datachanged", this);
11782 this.load(this.lastOptions);
11787 * Calls the specified function for each of the Records in the cache.
11788 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11789 * Returning <em>false</em> aborts and exits the iteration.
11790 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11792 each : function(fn, scope){
11793 this.data.each(fn, scope);
11797 * Gets all records modified since the last commit. Modified records are persisted across load operations
11798 * (e.g., during paging).
11799 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11801 getModifiedRecords : function(){
11802 return this.modified;
11806 createFilterFn : function(property, value, anyMatch){
11807 if(!value.exec){ // not a regex
11808 value = String(value);
11809 if(value.length == 0){
11812 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11814 return function(r){
11815 return value.test(r.data[property]);
11820 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11821 * @param {String} property A field on your records
11822 * @param {Number} start The record index to start at (defaults to 0)
11823 * @param {Number} end The last record index to include (defaults to length - 1)
11824 * @return {Number} The sum
11826 sum : function(property, start, end){
11827 var rs = this.data.items, v = 0;
11828 start = start || 0;
11829 end = (end || end === 0) ? end : rs.length-1;
11831 for(var i = start; i <= end; i++){
11832 v += (rs[i].data[property] || 0);
11838 * Filter the records by a specified property.
11839 * @param {String} field A field on your records
11840 * @param {String/RegExp} value Either a string that the field
11841 * should start with or a RegExp to test against the field
11842 * @param {Boolean} anyMatch True to match any part not just the beginning
11844 filter : function(property, value, anyMatch){
11845 var fn = this.createFilterFn(property, value, anyMatch);
11846 return fn ? this.filterBy(fn) : this.clearFilter();
11850 * Filter by a function. The specified function will be called with each
11851 * record in this data source. If the function returns true the record is included,
11852 * otherwise it is filtered.
11853 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11854 * @param {Object} scope (optional) The scope of the function (defaults to this)
11856 filterBy : function(fn, scope){
11857 this.snapshot = this.snapshot || this.data;
11858 this.data = this.queryBy(fn, scope||this);
11859 this.fireEvent("datachanged", this);
11863 * Query the records by a specified property.
11864 * @param {String} field A field on your records
11865 * @param {String/RegExp} value Either a string that the field
11866 * should start with or a RegExp to test against the field
11867 * @param {Boolean} anyMatch True to match any part not just the beginning
11868 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11870 query : function(property, value, anyMatch){
11871 var fn = this.createFilterFn(property, value, anyMatch);
11872 return fn ? this.queryBy(fn) : this.data.clone();
11876 * Query by a function. The specified function will be called with each
11877 * record in this data source. If the function returns true the record is included
11879 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11880 * @param {Object} scope (optional) The scope of the function (defaults to this)
11881 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11883 queryBy : function(fn, scope){
11884 var data = this.snapshot || this.data;
11885 return data.filterBy(fn, scope||this);
11889 * Collects unique values for a particular dataIndex from this store.
11890 * @param {String} dataIndex The property to collect
11891 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11892 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11893 * @return {Array} An array of the unique values
11895 collect : function(dataIndex, allowNull, bypassFilter){
11896 var d = (bypassFilter === true && this.snapshot) ?
11897 this.snapshot.items : this.data.items;
11898 var v, sv, r = [], l = {};
11899 for(var i = 0, len = d.length; i < len; i++){
11900 v = d[i].data[dataIndex];
11902 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11911 * Revert to a view of the Record cache with no filtering applied.
11912 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11914 clearFilter : function(suppressEvent){
11915 if(this.snapshot && this.snapshot != this.data){
11916 this.data = this.snapshot;
11917 delete this.snapshot;
11918 if(suppressEvent !== true){
11919 this.fireEvent("datachanged", this);
11925 afterEdit : function(record){
11926 if(this.modified.indexOf(record) == -1){
11927 this.modified.push(record);
11929 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11933 afterReject : function(record){
11934 this.modified.remove(record);
11935 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11939 afterCommit : function(record){
11940 this.modified.remove(record);
11941 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11945 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11946 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11948 commitChanges : function(){
11949 var m = this.modified.slice(0);
11950 this.modified = [];
11951 for(var i = 0, len = m.length; i < len; i++){
11957 * Cancel outstanding changes on all changed records.
11959 rejectChanges : function(){
11960 var m = this.modified.slice(0);
11961 this.modified = [];
11962 for(var i = 0, len = m.length; i < len; i++){
11967 onMetaChange : function(meta, rtype, o){
11968 this.recordType = rtype;
11969 this.fields = rtype.prototype.fields;
11970 delete this.snapshot;
11971 this.sortInfo = meta.sortInfo || this.sortInfo;
11972 this.modified = [];
11973 this.fireEvent('metachange', this, this.reader.meta);
11976 moveIndex : function(data, type)
11978 var index = this.indexOf(data);
11980 var newIndex = index + type;
11984 this.insert(newIndex, data);
11989 * Ext JS Library 1.1.1
11990 * Copyright(c) 2006-2007, Ext JS, LLC.
11992 * Originally Released Under LGPL - original licence link has changed is not relivant.
11995 * <script type="text/javascript">
11999 * @class Roo.data.SimpleStore
12000 * @extends Roo.data.Store
12001 * Small helper class to make creating Stores from Array data easier.
12002 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12003 * @cfg {Array} fields An array of field definition objects, or field name strings.
12004 * @cfg {Array} data The multi-dimensional array of data
12006 * @param {Object} config
12008 Roo.data.SimpleStore = function(config){
12009 Roo.data.SimpleStore.superclass.constructor.call(this, {
12011 reader: new Roo.data.ArrayReader({
12014 Roo.data.Record.create(config.fields)
12016 proxy : new Roo.data.MemoryProxy(config.data)
12020 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12022 * Ext JS Library 1.1.1
12023 * Copyright(c) 2006-2007, Ext JS, LLC.
12025 * Originally Released Under LGPL - original licence link has changed is not relivant.
12028 * <script type="text/javascript">
12033 * @extends Roo.data.Store
12034 * @class Roo.data.JsonStore
12035 * Small helper class to make creating Stores for JSON data easier. <br/>
12037 var store = new Roo.data.JsonStore({
12038 url: 'get-images.php',
12040 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12043 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12044 * JsonReader and HttpProxy (unless inline data is provided).</b>
12045 * @cfg {Array} fields An array of field definition objects, or field name strings.
12047 * @param {Object} config
12049 Roo.data.JsonStore = function(c){
12050 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12051 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12052 reader: new Roo.data.JsonReader(c, c.fields)
12055 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12057 * Ext JS Library 1.1.1
12058 * Copyright(c) 2006-2007, Ext JS, LLC.
12060 * Originally Released Under LGPL - original licence link has changed is not relivant.
12063 * <script type="text/javascript">
12067 Roo.data.Field = function(config){
12068 if(typeof config == "string"){
12069 config = {name: config};
12071 Roo.apply(this, config);
12074 this.type = "auto";
12077 var st = Roo.data.SortTypes;
12078 // named sortTypes are supported, here we look them up
12079 if(typeof this.sortType == "string"){
12080 this.sortType = st[this.sortType];
12083 // set default sortType for strings and dates
12084 if(!this.sortType){
12087 this.sortType = st.asUCString;
12090 this.sortType = st.asDate;
12093 this.sortType = st.none;
12098 var stripRe = /[\$,%]/g;
12100 // prebuilt conversion function for this field, instead of
12101 // switching every time we're reading a value
12103 var cv, dateFormat = this.dateFormat;
12108 cv = function(v){ return v; };
12111 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12115 return v !== undefined && v !== null && v !== '' ?
12116 parseInt(String(v).replace(stripRe, ""), 10) : '';
12121 return v !== undefined && v !== null && v !== '' ?
12122 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12127 cv = function(v){ return v === true || v === "true" || v == 1; };
12134 if(v instanceof Date){
12138 if(dateFormat == "timestamp"){
12139 return new Date(v*1000);
12141 return Date.parseDate(v, dateFormat);
12143 var parsed = Date.parse(v);
12144 return parsed ? new Date(parsed) : null;
12153 Roo.data.Field.prototype = {
12161 * Ext JS Library 1.1.1
12162 * Copyright(c) 2006-2007, Ext JS, LLC.
12164 * Originally Released Under LGPL - original licence link has changed is not relivant.
12167 * <script type="text/javascript">
12170 // Base class for reading structured data from a data source. This class is intended to be
12171 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12174 * @class Roo.data.DataReader
12175 * Base class for reading structured data from a data source. This class is intended to be
12176 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12179 Roo.data.DataReader = function(meta, recordType){
12183 this.recordType = recordType instanceof Array ?
12184 Roo.data.Record.create(recordType) : recordType;
12187 Roo.data.DataReader.prototype = {
12189 * Create an empty record
12190 * @param {Object} data (optional) - overlay some values
12191 * @return {Roo.data.Record} record created.
12193 newRow : function(d) {
12195 this.recordType.prototype.fields.each(function(c) {
12197 case 'int' : da[c.name] = 0; break;
12198 case 'date' : da[c.name] = new Date(); break;
12199 case 'float' : da[c.name] = 0.0; break;
12200 case 'boolean' : da[c.name] = false; break;
12201 default : da[c.name] = ""; break;
12205 return new this.recordType(Roo.apply(da, d));
12210 * Ext JS Library 1.1.1
12211 * Copyright(c) 2006-2007, Ext JS, LLC.
12213 * Originally Released Under LGPL - original licence link has changed is not relivant.
12216 * <script type="text/javascript">
12220 * @class Roo.data.DataProxy
12221 * @extends Roo.data.Observable
12222 * This class is an abstract base class for implementations which provide retrieval of
12223 * unformatted data objects.<br>
12225 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12226 * (of the appropriate type which knows how to parse the data object) to provide a block of
12227 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12229 * Custom implementations must implement the load method as described in
12230 * {@link Roo.data.HttpProxy#load}.
12232 Roo.data.DataProxy = function(){
12235 * @event beforeload
12236 * Fires before a network request is made to retrieve a data object.
12237 * @param {Object} This DataProxy object.
12238 * @param {Object} params The params parameter to the load function.
12243 * Fires before the load method's callback is called.
12244 * @param {Object} This DataProxy object.
12245 * @param {Object} o The data object.
12246 * @param {Object} arg The callback argument object passed to the load function.
12250 * @event loadexception
12251 * Fires if an Exception occurs during data retrieval.
12252 * @param {Object} This DataProxy object.
12253 * @param {Object} o The data object.
12254 * @param {Object} arg The callback argument object passed to the load function.
12255 * @param {Object} e The Exception.
12257 loadexception : true
12259 Roo.data.DataProxy.superclass.constructor.call(this);
12262 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12265 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12269 * Ext JS Library 1.1.1
12270 * Copyright(c) 2006-2007, Ext JS, LLC.
12272 * Originally Released Under LGPL - original licence link has changed is not relivant.
12275 * <script type="text/javascript">
12278 * @class Roo.data.MemoryProxy
12279 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12280 * to the Reader when its load method is called.
12282 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12284 Roo.data.MemoryProxy = function(data){
12288 Roo.data.MemoryProxy.superclass.constructor.call(this);
12292 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12295 * Load data from the requested source (in this case an in-memory
12296 * data object passed to the constructor), read the data object into
12297 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12298 * process that block using the passed callback.
12299 * @param {Object} params This parameter is not used by the MemoryProxy class.
12300 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12301 * object into a block of Roo.data.Records.
12302 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12303 * The function must be passed <ul>
12304 * <li>The Record block object</li>
12305 * <li>The "arg" argument from the load function</li>
12306 * <li>A boolean success indicator</li>
12308 * @param {Object} scope The scope in which to call the callback
12309 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12311 load : function(params, reader, callback, scope, arg){
12312 params = params || {};
12315 result = reader.readRecords(this.data);
12317 this.fireEvent("loadexception", this, arg, null, e);
12318 callback.call(scope, null, arg, false);
12321 callback.call(scope, result, arg, true);
12325 update : function(params, records){
12330 * Ext JS Library 1.1.1
12331 * Copyright(c) 2006-2007, Ext JS, LLC.
12333 * Originally Released Under LGPL - original licence link has changed is not relivant.
12336 * <script type="text/javascript">
12339 * @class Roo.data.HttpProxy
12340 * @extends Roo.data.DataProxy
12341 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12342 * configured to reference a certain URL.<br><br>
12344 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12345 * from which the running page was served.<br><br>
12347 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12349 * Be aware that to enable the browser to parse an XML document, the server must set
12350 * the Content-Type header in the HTTP response to "text/xml".
12352 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12353 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12354 * will be used to make the request.
12356 Roo.data.HttpProxy = function(conn){
12357 Roo.data.HttpProxy.superclass.constructor.call(this);
12358 // is conn a conn config or a real conn?
12360 this.useAjax = !conn || !conn.events;
12364 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12365 // thse are take from connection...
12368 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12371 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12372 * extra parameters to each request made by this object. (defaults to undefined)
12375 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12376 * to each request made by this object. (defaults to undefined)
12379 * @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)
12382 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12385 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12391 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12395 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12396 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12397 * a finer-grained basis than the DataProxy events.
12399 getConnection : function(){
12400 return this.useAjax ? Roo.Ajax : this.conn;
12404 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12405 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12406 * process that block using the passed callback.
12407 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12408 * for the request to the remote server.
12409 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12410 * object into a block of Roo.data.Records.
12411 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12412 * The function must be passed <ul>
12413 * <li>The Record block object</li>
12414 * <li>The "arg" argument from the load function</li>
12415 * <li>A boolean success indicator</li>
12417 * @param {Object} scope The scope in which to call the callback
12418 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12420 load : function(params, reader, callback, scope, arg){
12421 if(this.fireEvent("beforeload", this, params) !== false){
12423 params : params || {},
12425 callback : callback,
12430 callback : this.loadResponse,
12434 Roo.applyIf(o, this.conn);
12435 if(this.activeRequest){
12436 Roo.Ajax.abort(this.activeRequest);
12438 this.activeRequest = Roo.Ajax.request(o);
12440 this.conn.request(o);
12443 callback.call(scope||this, null, arg, false);
12448 loadResponse : function(o, success, response){
12449 delete this.activeRequest;
12451 this.fireEvent("loadexception", this, o, response);
12452 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12457 result = o.reader.read(response);
12459 this.fireEvent("loadexception", this, o, response, e);
12460 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12464 this.fireEvent("load", this, o, o.request.arg);
12465 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12469 update : function(dataSet){
12474 updateResponse : function(dataSet){
12479 * Ext JS Library 1.1.1
12480 * Copyright(c) 2006-2007, Ext JS, LLC.
12482 * Originally Released Under LGPL - original licence link has changed is not relivant.
12485 * <script type="text/javascript">
12489 * @class Roo.data.ScriptTagProxy
12490 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12491 * other than the originating domain of the running page.<br><br>
12493 * <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
12494 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12496 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12497 * source code that is used as the source inside a <script> tag.<br><br>
12499 * In order for the browser to process the returned data, the server must wrap the data object
12500 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12501 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12502 * depending on whether the callback name was passed:
12505 boolean scriptTag = false;
12506 String cb = request.getParameter("callback");
12509 response.setContentType("text/javascript");
12511 response.setContentType("application/x-json");
12513 Writer out = response.getWriter();
12515 out.write(cb + "(");
12517 out.print(dataBlock.toJsonString());
12524 * @param {Object} config A configuration object.
12526 Roo.data.ScriptTagProxy = function(config){
12527 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12528 Roo.apply(this, config);
12529 this.head = document.getElementsByTagName("head")[0];
12532 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12534 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12536 * @cfg {String} url The URL from which to request the data object.
12539 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12543 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12544 * the server the name of the callback function set up by the load call to process the returned data object.
12545 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12546 * javascript output which calls this named function passing the data object as its only parameter.
12548 callbackParam : "callback",
12550 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12551 * name to the request.
12556 * Load data from the configured URL, read the data object into
12557 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12558 * process that block using the passed callback.
12559 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12560 * for the request to the remote server.
12561 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12562 * object into a block of Roo.data.Records.
12563 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12564 * The function must be passed <ul>
12565 * <li>The Record block object</li>
12566 * <li>The "arg" argument from the load function</li>
12567 * <li>A boolean success indicator</li>
12569 * @param {Object} scope The scope in which to call the callback
12570 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12572 load : function(params, reader, callback, scope, arg){
12573 if(this.fireEvent("beforeload", this, params) !== false){
12575 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12577 var url = this.url;
12578 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12580 url += "&_dc=" + (new Date().getTime());
12582 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12585 cb : "stcCallback"+transId,
12586 scriptId : "stcScript"+transId,
12590 callback : callback,
12596 window[trans.cb] = function(o){
12597 conn.handleResponse(o, trans);
12600 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12602 if(this.autoAbort !== false){
12606 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12608 var script = document.createElement("script");
12609 script.setAttribute("src", url);
12610 script.setAttribute("type", "text/javascript");
12611 script.setAttribute("id", trans.scriptId);
12612 this.head.appendChild(script);
12614 this.trans = trans;
12616 callback.call(scope||this, null, arg, false);
12621 isLoading : function(){
12622 return this.trans ? true : false;
12626 * Abort the current server request.
12628 abort : function(){
12629 if(this.isLoading()){
12630 this.destroyTrans(this.trans);
12635 destroyTrans : function(trans, isLoaded){
12636 this.head.removeChild(document.getElementById(trans.scriptId));
12637 clearTimeout(trans.timeoutId);
12639 window[trans.cb] = undefined;
12641 delete window[trans.cb];
12644 // if hasn't been loaded, wait for load to remove it to prevent script error
12645 window[trans.cb] = function(){
12646 window[trans.cb] = undefined;
12648 delete window[trans.cb];
12655 handleResponse : function(o, trans){
12656 this.trans = false;
12657 this.destroyTrans(trans, true);
12660 result = trans.reader.readRecords(o);
12662 this.fireEvent("loadexception", this, o, trans.arg, e);
12663 trans.callback.call(trans.scope||window, null, trans.arg, false);
12666 this.fireEvent("load", this, o, trans.arg);
12667 trans.callback.call(trans.scope||window, result, trans.arg, true);
12671 handleFailure : function(trans){
12672 this.trans = false;
12673 this.destroyTrans(trans, false);
12674 this.fireEvent("loadexception", this, null, trans.arg);
12675 trans.callback.call(trans.scope||window, null, trans.arg, false);
12679 * Ext JS Library 1.1.1
12680 * Copyright(c) 2006-2007, Ext JS, LLC.
12682 * Originally Released Under LGPL - original licence link has changed is not relivant.
12685 * <script type="text/javascript">
12689 * @class Roo.data.JsonReader
12690 * @extends Roo.data.DataReader
12691 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12692 * based on mappings in a provided Roo.data.Record constructor.
12694 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12695 * in the reply previously.
12700 var RecordDef = Roo.data.Record.create([
12701 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12702 {name: 'occupation'} // This field will use "occupation" as the mapping.
12704 var myReader = new Roo.data.JsonReader({
12705 totalProperty: "results", // The property which contains the total dataset size (optional)
12706 root: "rows", // The property which contains an Array of row objects
12707 id: "id" // The property within each row object that provides an ID for the record (optional)
12711 * This would consume a JSON file like this:
12713 { 'results': 2, 'rows': [
12714 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12715 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12718 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12719 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12720 * paged from the remote server.
12721 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12722 * @cfg {String} root name of the property which contains the Array of row objects.
12723 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12724 * @cfg {Array} fields Array of field definition objects
12726 * Create a new JsonReader
12727 * @param {Object} meta Metadata configuration options
12728 * @param {Object} recordType Either an Array of field definition objects,
12729 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12731 Roo.data.JsonReader = function(meta, recordType){
12734 // set some defaults:
12735 Roo.applyIf(meta, {
12736 totalProperty: 'total',
12737 successProperty : 'success',
12742 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12744 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12747 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12748 * Used by Store query builder to append _requestMeta to params.
12751 metaFromRemote : false,
12753 * This method is only used by a DataProxy which has retrieved data from a remote server.
12754 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12755 * @return {Object} data A data block which is used by an Roo.data.Store object as
12756 * a cache of Roo.data.Records.
12758 read : function(response){
12759 var json = response.responseText;
12761 var o = /* eval:var:o */ eval("("+json+")");
12763 throw {message: "JsonReader.read: Json object not found"};
12769 this.metaFromRemote = true;
12770 this.meta = o.metaData;
12771 this.recordType = Roo.data.Record.create(o.metaData.fields);
12772 this.onMetaChange(this.meta, this.recordType, o);
12774 return this.readRecords(o);
12777 // private function a store will implement
12778 onMetaChange : function(meta, recordType, o){
12785 simpleAccess: function(obj, subsc) {
12792 getJsonAccessor: function(){
12794 return function(expr) {
12796 return(re.test(expr))
12797 ? new Function("obj", "return obj." + expr)
12802 return Roo.emptyFn;
12807 * Create a data block containing Roo.data.Records from an XML document.
12808 * @param {Object} o An object which contains an Array of row objects in the property specified
12809 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12810 * which contains the total size of the dataset.
12811 * @return {Object} data A data block which is used by an Roo.data.Store object as
12812 * a cache of Roo.data.Records.
12814 readRecords : function(o){
12816 * After any data loads, the raw JSON data is available for further custom processing.
12820 var s = this.meta, Record = this.recordType,
12821 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12823 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12825 if(s.totalProperty) {
12826 this.getTotal = this.getJsonAccessor(s.totalProperty);
12828 if(s.successProperty) {
12829 this.getSuccess = this.getJsonAccessor(s.successProperty);
12831 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12833 var g = this.getJsonAccessor(s.id);
12834 this.getId = function(rec) {
12836 return (r === undefined || r === "") ? null : r;
12839 this.getId = function(){return null;};
12842 for(var jj = 0; jj < fl; jj++){
12844 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12845 this.ef[jj] = this.getJsonAccessor(map);
12849 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12850 if(s.totalProperty){
12851 var vt = parseInt(this.getTotal(o), 10);
12856 if(s.successProperty){
12857 var vs = this.getSuccess(o);
12858 if(vs === false || vs === 'false'){
12863 for(var i = 0; i < c; i++){
12866 var id = this.getId(n);
12867 for(var j = 0; j < fl; j++){
12869 var v = this.ef[j](n);
12871 Roo.log('missing convert for ' + f.name);
12875 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12877 var record = new Record(values, id);
12879 records[i] = record;
12885 totalRecords : totalRecords
12890 * Ext JS Library 1.1.1
12891 * Copyright(c) 2006-2007, Ext JS, LLC.
12893 * Originally Released Under LGPL - original licence link has changed is not relivant.
12896 * <script type="text/javascript">
12900 * @class Roo.data.ArrayReader
12901 * @extends Roo.data.DataReader
12902 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12903 * Each element of that Array represents a row of data fields. The
12904 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12905 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12909 var RecordDef = Roo.data.Record.create([
12910 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12911 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12913 var myReader = new Roo.data.ArrayReader({
12914 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12918 * This would consume an Array like this:
12920 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12922 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12924 * Create a new JsonReader
12925 * @param {Object} meta Metadata configuration options.
12926 * @param {Object} recordType Either an Array of field definition objects
12927 * as specified to {@link Roo.data.Record#create},
12928 * or an {@link Roo.data.Record} object
12929 * created using {@link Roo.data.Record#create}.
12931 Roo.data.ArrayReader = function(meta, recordType){
12932 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12935 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12937 * Create a data block containing Roo.data.Records from an XML document.
12938 * @param {Object} o An Array of row objects which represents the dataset.
12939 * @return {Object} data A data block which is used by an Roo.data.Store object as
12940 * a cache of Roo.data.Records.
12942 readRecords : function(o){
12943 var sid = this.meta ? this.meta.id : null;
12944 var recordType = this.recordType, fields = recordType.prototype.fields;
12947 for(var i = 0; i < root.length; i++){
12950 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12951 for(var j = 0, jlen = fields.length; j < jlen; j++){
12952 var f = fields.items[j];
12953 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12954 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12956 values[f.name] = v;
12958 var record = new recordType(values, id);
12960 records[records.length] = record;
12964 totalRecords : records.length
12973 * @class Roo.bootstrap.ComboBox
12974 * @extends Roo.bootstrap.TriggerField
12975 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12976 * @cfg {Boolean} append (true|false) default false
12977 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12978 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12979 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12980 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12981 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12982 * @cfg {Boolean} animate default true
12983 * @cfg {Boolean} emptyResultText only for touch device
12984 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12985 * @cfg {String} emptyTitle default ''
12987 * Create a new ComboBox.
12988 * @param {Object} config Configuration options
12990 Roo.bootstrap.ComboBox = function(config){
12991 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12995 * Fires when the dropdown list is expanded
12996 * @param {Roo.bootstrap.ComboBox} combo This combo box
13001 * Fires when the dropdown list is collapsed
13002 * @param {Roo.bootstrap.ComboBox} combo This combo box
13006 * @event beforeselect
13007 * Fires before a list item is selected. Return false to cancel the selection.
13008 * @param {Roo.bootstrap.ComboBox} combo This combo box
13009 * @param {Roo.data.Record} record The data record returned from the underlying store
13010 * @param {Number} index The index of the selected item in the dropdown list
13012 'beforeselect' : true,
13015 * Fires when a list item is selected
13016 * @param {Roo.bootstrap.ComboBox} combo This combo box
13017 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13018 * @param {Number} index The index of the selected item in the dropdown list
13022 * @event beforequery
13023 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13024 * The event object passed has these properties:
13025 * @param {Roo.bootstrap.ComboBox} combo This combo box
13026 * @param {String} query The query
13027 * @param {Boolean} forceAll true to force "all" query
13028 * @param {Boolean} cancel true to cancel the query
13029 * @param {Object} e The query event object
13031 'beforequery': true,
13034 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13035 * @param {Roo.bootstrap.ComboBox} combo This combo box
13040 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13041 * @param {Roo.bootstrap.ComboBox} combo This combo box
13042 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13047 * Fires when the remove value from the combobox array
13048 * @param {Roo.bootstrap.ComboBox} combo This combo box
13052 * @event afterremove
13053 * Fires when the remove value from the combobox array
13054 * @param {Roo.bootstrap.ComboBox} combo This combo box
13056 'afterremove' : true,
13058 * @event specialfilter
13059 * Fires when specialfilter
13060 * @param {Roo.bootstrap.ComboBox} combo This combo box
13062 'specialfilter' : true,
13065 * Fires when tick the element
13066 * @param {Roo.bootstrap.ComboBox} combo This combo box
13070 * @event touchviewdisplay
13071 * Fires when touch view require special display (default is using displayField)
13072 * @param {Roo.bootstrap.ComboBox} combo This combo box
13073 * @param {Object} cfg set html .
13075 'touchviewdisplay' : true
13080 this.tickItems = [];
13082 this.selectedIndex = -1;
13083 if(this.mode == 'local'){
13084 if(config.queryDelay === undefined){
13085 this.queryDelay = 10;
13087 if(config.minChars === undefined){
13093 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13096 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13097 * rendering into an Roo.Editor, defaults to false)
13100 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13101 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13104 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13107 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13108 * the dropdown list (defaults to undefined, with no header element)
13112 * @cfg {String/Roo.Template} tpl The template to use to render the output
13116 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13118 listWidth: undefined,
13120 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13121 * mode = 'remote' or 'text' if mode = 'local')
13123 displayField: undefined,
13126 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13127 * mode = 'remote' or 'value' if mode = 'local').
13128 * Note: use of a valueField requires the user make a selection
13129 * in order for a value to be mapped.
13131 valueField: undefined,
13133 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13138 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13139 * field's data value (defaults to the underlying DOM element's name)
13141 hiddenName: undefined,
13143 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13147 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13149 selectedClass: 'active',
13152 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13156 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13157 * anchor positions (defaults to 'tl-bl')
13159 listAlign: 'tl-bl?',
13161 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13165 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13166 * query specified by the allQuery config option (defaults to 'query')
13168 triggerAction: 'query',
13170 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13171 * (defaults to 4, does not apply if editable = false)
13175 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13176 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13180 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13181 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13185 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13186 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13190 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13191 * when editable = true (defaults to false)
13193 selectOnFocus:false,
13195 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13197 queryParam: 'query',
13199 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13200 * when mode = 'remote' (defaults to 'Loading...')
13202 loadingText: 'Loading...',
13204 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13208 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13212 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13213 * traditional select (defaults to true)
13217 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13221 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13225 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13226 * listWidth has a higher value)
13230 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13231 * allow the user to set arbitrary text into the field (defaults to false)
13233 forceSelection:false,
13235 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13236 * if typeAhead = true (defaults to 250)
13238 typeAheadDelay : 250,
13240 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13241 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13243 valueNotFoundText : undefined,
13245 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13247 blockFocus : false,
13250 * @cfg {Boolean} disableClear Disable showing of clear button.
13252 disableClear : false,
13254 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13256 alwaysQuery : false,
13259 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13264 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13266 invalidClass : "has-warning",
13269 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13271 validClass : "has-success",
13274 * @cfg {Boolean} specialFilter (true|false) special filter default false
13276 specialFilter : false,
13279 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13281 mobileTouchView : true,
13284 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13286 useNativeIOS : false,
13289 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13291 mobile_restrict_height : false,
13293 ios_options : false,
13305 btnPosition : 'right',
13306 triggerList : true,
13307 showToggleBtn : true,
13309 emptyResultText: 'Empty',
13310 triggerText : 'Select',
13313 // element that contains real text value.. (when hidden is used..)
13315 getAutoCreate : function()
13320 * Render classic select for iso
13323 if(Roo.isIOS && this.useNativeIOS){
13324 cfg = this.getAutoCreateNativeIOS();
13332 if(Roo.isTouch && this.mobileTouchView){
13333 cfg = this.getAutoCreateTouchView();
13340 if(!this.tickable){
13341 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13346 * ComboBox with tickable selections
13349 var align = this.labelAlign || this.parentLabelAlign();
13352 cls : 'form-group roo-combobox-tickable' //input-group
13355 var btn_text_select = '';
13356 var btn_text_done = '';
13357 var btn_text_cancel = '';
13359 if (this.btn_text_show) {
13360 btn_text_select = 'Select';
13361 btn_text_done = 'Done';
13362 btn_text_cancel = 'Cancel';
13367 cls : 'tickable-buttons',
13372 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13373 //html : this.triggerText
13374 html: btn_text_select
13380 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13382 html: btn_text_done
13388 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13390 html: btn_text_cancel
13396 buttons.cn.unshift({
13398 cls: 'roo-select2-search-field-input'
13404 Roo.each(buttons.cn, function(c){
13406 c.cls += ' btn-' + _this.size;
13409 if (_this.disabled) {
13416 style : 'display: contents',
13421 cls: 'form-hidden-field'
13425 cls: 'roo-select2-choices',
13429 cls: 'roo-select2-search-field',
13440 cls: 'roo-select2-container input-group roo-select2-container-multi',
13446 // cls: 'typeahead typeahead-long dropdown-menu',
13447 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13452 if(this.hasFeedback && !this.allowBlank){
13456 cls: 'glyphicon form-control-feedback'
13459 combobox.cn.push(feedback);
13464 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13465 tooltip : 'This field is required'
13467 if (Roo.bootstrap.version == 4) {
13470 style : 'display:none'
13473 if (align ==='left' && this.fieldLabel.length) {
13475 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13482 cls : 'control-label col-form-label',
13483 html : this.fieldLabel
13495 var labelCfg = cfg.cn[1];
13496 var contentCfg = cfg.cn[2];
13499 if(this.indicatorpos == 'right'){
13505 cls : 'control-label col-form-label',
13509 html : this.fieldLabel
13525 labelCfg = cfg.cn[0];
13526 contentCfg = cfg.cn[1];
13530 if(this.labelWidth > 12){
13531 labelCfg.style = "width: " + this.labelWidth + 'px';
13534 if(this.labelWidth < 13 && this.labelmd == 0){
13535 this.labelmd = this.labelWidth;
13538 if(this.labellg > 0){
13539 labelCfg.cls += ' col-lg-' + this.labellg;
13540 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13543 if(this.labelmd > 0){
13544 labelCfg.cls += ' col-md-' + this.labelmd;
13545 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13548 if(this.labelsm > 0){
13549 labelCfg.cls += ' col-sm-' + this.labelsm;
13550 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13553 if(this.labelxs > 0){
13554 labelCfg.cls += ' col-xs-' + this.labelxs;
13555 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13559 } else if ( this.fieldLabel.length) {
13560 // Roo.log(" label");
13565 //cls : 'input-group-addon',
13566 html : this.fieldLabel
13571 if(this.indicatorpos == 'right'){
13575 //cls : 'input-group-addon',
13576 html : this.fieldLabel
13586 // Roo.log(" no label && no align");
13593 ['xs','sm','md','lg'].map(function(size){
13594 if (settings[size]) {
13595 cfg.cls += ' col-' + size + '-' + settings[size];
13603 _initEventsCalled : false,
13606 initEvents: function()
13608 if (this._initEventsCalled) { // as we call render... prevent looping...
13611 this._initEventsCalled = true;
13614 throw "can not find store for combo";
13617 this.indicator = this.indicatorEl();
13619 this.store = Roo.factory(this.store, Roo.data);
13620 this.store.parent = this;
13622 // if we are building from html. then this element is so complex, that we can not really
13623 // use the rendered HTML.
13624 // so we have to trash and replace the previous code.
13625 if (Roo.XComponent.build_from_html) {
13626 // remove this element....
13627 var e = this.el.dom, k=0;
13628 while (e ) { e = e.previousSibling; ++k;}
13633 this.rendered = false;
13635 this.render(this.parent().getChildContainer(true), k);
13638 if(Roo.isIOS && this.useNativeIOS){
13639 this.initIOSView();
13647 if(Roo.isTouch && this.mobileTouchView){
13648 this.initTouchView();
13653 this.initTickableEvents();
13657 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13659 if(this.hiddenName){
13661 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13663 this.hiddenField.dom.value =
13664 this.hiddenValue !== undefined ? this.hiddenValue :
13665 this.value !== undefined ? this.value : '';
13667 // prevent input submission
13668 this.el.dom.removeAttribute('name');
13669 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13674 // this.el.dom.setAttribute('autocomplete', 'off');
13677 var cls = 'x-combo-list';
13679 //this.list = new Roo.Layer({
13680 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13686 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13687 _this.list.setWidth(lw);
13690 this.list.on('mouseover', this.onViewOver, this);
13691 this.list.on('mousemove', this.onViewMove, this);
13692 this.list.on('scroll', this.onViewScroll, this);
13695 this.list.swallowEvent('mousewheel');
13696 this.assetHeight = 0;
13699 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13700 this.assetHeight += this.header.getHeight();
13703 this.innerList = this.list.createChild({cls:cls+'-inner'});
13704 this.innerList.on('mouseover', this.onViewOver, this);
13705 this.innerList.on('mousemove', this.onViewMove, this);
13706 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13708 if(this.allowBlank && !this.pageSize && !this.disableClear){
13709 this.footer = this.list.createChild({cls:cls+'-ft'});
13710 this.pageTb = new Roo.Toolbar(this.footer);
13714 this.footer = this.list.createChild({cls:cls+'-ft'});
13715 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13716 {pageSize: this.pageSize});
13720 if (this.pageTb && this.allowBlank && !this.disableClear) {
13722 this.pageTb.add(new Roo.Toolbar.Fill(), {
13723 cls: 'x-btn-icon x-btn-clear',
13725 handler: function()
13728 _this.clearValue();
13729 _this.onSelect(false, -1);
13734 this.assetHeight += this.footer.getHeight();
13739 this.tpl = Roo.bootstrap.version == 4 ?
13740 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13741 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13744 this.view = new Roo.View(this.list, this.tpl, {
13745 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13747 //this.view.wrapEl.setDisplayed(false);
13748 this.view.on('click', this.onViewClick, this);
13751 this.store.on('beforeload', this.onBeforeLoad, this);
13752 this.store.on('load', this.onLoad, this);
13753 this.store.on('loadexception', this.onLoadException, this);
13755 if(this.resizable){
13756 this.resizer = new Roo.Resizable(this.list, {
13757 pinned:true, handles:'se'
13759 this.resizer.on('resize', function(r, w, h){
13760 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13761 this.listWidth = w;
13762 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13763 this.restrictHeight();
13765 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13768 if(!this.editable){
13769 this.editable = true;
13770 this.setEditable(false);
13775 if (typeof(this.events.add.listeners) != 'undefined') {
13777 this.addicon = this.wrap.createChild(
13778 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13780 this.addicon.on('click', function(e) {
13781 this.fireEvent('add', this);
13784 if (typeof(this.events.edit.listeners) != 'undefined') {
13786 this.editicon = this.wrap.createChild(
13787 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13788 if (this.addicon) {
13789 this.editicon.setStyle('margin-left', '40px');
13791 this.editicon.on('click', function(e) {
13793 // we fire even if inothing is selected..
13794 this.fireEvent('edit', this, this.lastData );
13800 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13801 "up" : function(e){
13802 this.inKeyMode = true;
13806 "down" : function(e){
13807 if(!this.isExpanded()){
13808 this.onTriggerClick();
13810 this.inKeyMode = true;
13815 "enter" : function(e){
13816 // this.onViewClick();
13820 if(this.fireEvent("specialkey", this, e)){
13821 this.onViewClick(false);
13827 "esc" : function(e){
13831 "tab" : function(e){
13834 if(this.fireEvent("specialkey", this, e)){
13835 this.onViewClick(false);
13843 doRelay : function(foo, bar, hname){
13844 if(hname == 'down' || this.scope.isExpanded()){
13845 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13854 this.queryDelay = Math.max(this.queryDelay || 10,
13855 this.mode == 'local' ? 10 : 250);
13858 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13860 if(this.typeAhead){
13861 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13863 if(this.editable !== false){
13864 this.inputEl().on("keyup", this.onKeyUp, this);
13866 if(this.forceSelection){
13867 this.inputEl().on('blur', this.doForce, this);
13871 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13872 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13876 initTickableEvents: function()
13880 if(this.hiddenName){
13882 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13884 this.hiddenField.dom.value =
13885 this.hiddenValue !== undefined ? this.hiddenValue :
13886 this.value !== undefined ? this.value : '';
13888 // prevent input submission
13889 this.el.dom.removeAttribute('name');
13890 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13895 // this.list = this.el.select('ul.dropdown-menu',true).first();
13897 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13898 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13899 if(this.triggerList){
13900 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13903 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13904 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13906 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13907 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13909 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13910 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13912 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13913 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13914 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13917 this.cancelBtn.hide();
13922 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13923 _this.list.setWidth(lw);
13926 this.list.on('mouseover', this.onViewOver, this);
13927 this.list.on('mousemove', this.onViewMove, this);
13929 this.list.on('scroll', this.onViewScroll, this);
13932 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13933 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13936 this.view = new Roo.View(this.list, this.tpl, {
13941 selectedClass: this.selectedClass
13944 //this.view.wrapEl.setDisplayed(false);
13945 this.view.on('click', this.onViewClick, this);
13949 this.store.on('beforeload', this.onBeforeLoad, this);
13950 this.store.on('load', this.onLoad, this);
13951 this.store.on('loadexception', this.onLoadException, this);
13954 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13955 "up" : function(e){
13956 this.inKeyMode = true;
13960 "down" : function(e){
13961 this.inKeyMode = true;
13965 "enter" : function(e){
13966 if(this.fireEvent("specialkey", this, e)){
13967 this.onViewClick(false);
13973 "esc" : function(e){
13974 this.onTickableFooterButtonClick(e, false, false);
13977 "tab" : function(e){
13978 this.fireEvent("specialkey", this, e);
13980 this.onTickableFooterButtonClick(e, false, false);
13987 doRelay : function(e, fn, key){
13988 if(this.scope.isExpanded()){
13989 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13998 this.queryDelay = Math.max(this.queryDelay || 10,
13999 this.mode == 'local' ? 10 : 250);
14002 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14004 if(this.typeAhead){
14005 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14008 if(this.editable !== false){
14009 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14012 this.indicator = this.indicatorEl();
14014 if(this.indicator){
14015 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14016 this.indicator.hide();
14021 onDestroy : function(){
14023 this.view.setStore(null);
14024 this.view.el.removeAllListeners();
14025 this.view.el.remove();
14026 this.view.purgeListeners();
14029 this.list.dom.innerHTML = '';
14033 this.store.un('beforeload', this.onBeforeLoad, this);
14034 this.store.un('load', this.onLoad, this);
14035 this.store.un('loadexception', this.onLoadException, this);
14037 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14041 fireKey : function(e){
14042 if(e.isNavKeyPress() && !this.list.isVisible()){
14043 this.fireEvent("specialkey", this, e);
14048 onResize: function(w, h){
14049 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14051 // if(typeof w != 'number'){
14052 // // we do not handle it!?!?
14055 // var tw = this.trigger.getWidth();
14056 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14057 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14059 // this.inputEl().setWidth( this.adjustWidth('input', x));
14061 // //this.trigger.setStyle('left', x+'px');
14063 // if(this.list && this.listWidth === undefined){
14064 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14065 // this.list.setWidth(lw);
14066 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14074 * Allow or prevent the user from directly editing the field text. If false is passed,
14075 * the user will only be able to select from the items defined in the dropdown list. This method
14076 * is the runtime equivalent of setting the 'editable' config option at config time.
14077 * @param {Boolean} value True to allow the user to directly edit the field text
14079 setEditable : function(value){
14080 if(value == this.editable){
14083 this.editable = value;
14085 this.inputEl().dom.setAttribute('readOnly', true);
14086 this.inputEl().on('mousedown', this.onTriggerClick, this);
14087 this.inputEl().addClass('x-combo-noedit');
14089 this.inputEl().dom.setAttribute('readOnly', false);
14090 this.inputEl().un('mousedown', this.onTriggerClick, this);
14091 this.inputEl().removeClass('x-combo-noedit');
14097 onBeforeLoad : function(combo,opts){
14098 if(!this.hasFocus){
14102 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14104 this.restrictHeight();
14105 this.selectedIndex = -1;
14109 onLoad : function(){
14111 this.hasQuery = false;
14113 if(!this.hasFocus){
14117 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14118 this.loading.hide();
14121 if(this.store.getCount() > 0){
14124 this.restrictHeight();
14125 if(this.lastQuery == this.allQuery){
14126 if(this.editable && !this.tickable){
14127 this.inputEl().dom.select();
14131 !this.selectByValue(this.value, true) &&
14134 !this.store.lastOptions ||
14135 typeof(this.store.lastOptions.add) == 'undefined' ||
14136 this.store.lastOptions.add != true
14139 this.select(0, true);
14142 if(this.autoFocus){
14145 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14146 this.taTask.delay(this.typeAheadDelay);
14150 this.onEmptyResults();
14156 onLoadException : function()
14158 this.hasQuery = false;
14160 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14161 this.loading.hide();
14164 if(this.tickable && this.editable){
14169 // only causes errors at present
14170 //Roo.log(this.store.reader.jsonData);
14171 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14173 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14179 onTypeAhead : function(){
14180 if(this.store.getCount() > 0){
14181 var r = this.store.getAt(0);
14182 var newValue = r.data[this.displayField];
14183 var len = newValue.length;
14184 var selStart = this.getRawValue().length;
14186 if(selStart != len){
14187 this.setRawValue(newValue);
14188 this.selectText(selStart, newValue.length);
14194 onSelect : function(record, index){
14196 if(this.fireEvent('beforeselect', this, record, index) !== false){
14198 this.setFromData(index > -1 ? record.data : false);
14201 this.fireEvent('select', this, record, index);
14206 * Returns the currently selected field value or empty string if no value is set.
14207 * @return {String} value The selected value
14209 getValue : function()
14211 if(Roo.isIOS && this.useNativeIOS){
14212 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14216 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14219 if(this.valueField){
14220 return typeof this.value != 'undefined' ? this.value : '';
14222 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14226 getRawValue : function()
14228 if(Roo.isIOS && this.useNativeIOS){
14229 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14232 var v = this.inputEl().getValue();
14238 * Clears any text/value currently set in the field
14240 clearValue : function(){
14242 if(this.hiddenField){
14243 this.hiddenField.dom.value = '';
14246 this.setRawValue('');
14247 this.lastSelectionText = '';
14248 this.lastData = false;
14250 var close = this.closeTriggerEl();
14261 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14262 * will be displayed in the field. If the value does not match the data value of an existing item,
14263 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14264 * Otherwise the field will be blank (although the value will still be set).
14265 * @param {String} value The value to match
14267 setValue : function(v)
14269 if(Roo.isIOS && this.useNativeIOS){
14270 this.setIOSValue(v);
14280 if(this.valueField){
14281 var r = this.findRecord(this.valueField, v);
14283 text = r.data[this.displayField];
14284 }else if(this.valueNotFoundText !== undefined){
14285 text = this.valueNotFoundText;
14288 this.lastSelectionText = text;
14289 if(this.hiddenField){
14290 this.hiddenField.dom.value = v;
14292 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14295 var close = this.closeTriggerEl();
14298 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14304 * @property {Object} the last set data for the element
14309 * Sets the value of the field based on a object which is related to the record format for the store.
14310 * @param {Object} value the value to set as. or false on reset?
14312 setFromData : function(o){
14319 var dv = ''; // display value
14320 var vv = ''; // value value..
14322 if (this.displayField) {
14323 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14325 // this is an error condition!!!
14326 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14329 if(this.valueField){
14330 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14333 var close = this.closeTriggerEl();
14336 if(dv.length || vv * 1 > 0){
14338 this.blockFocus=true;
14344 if(this.hiddenField){
14345 this.hiddenField.dom.value = vv;
14347 this.lastSelectionText = dv;
14348 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14352 // no hidden field.. - we store the value in 'value', but still display
14353 // display field!!!!
14354 this.lastSelectionText = dv;
14355 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14362 reset : function(){
14363 // overridden so that last data is reset..
14370 this.setValue(this.originalValue);
14371 //this.clearInvalid();
14372 this.lastData = false;
14374 this.view.clearSelections();
14380 findRecord : function(prop, value){
14382 if(this.store.getCount() > 0){
14383 this.store.each(function(r){
14384 if(r.data[prop] == value){
14394 getName: function()
14396 // returns hidden if it's set..
14397 if (!this.rendered) {return ''};
14398 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14402 onViewMove : function(e, t){
14403 this.inKeyMode = false;
14407 onViewOver : function(e, t){
14408 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14411 var item = this.view.findItemFromChild(t);
14414 var index = this.view.indexOf(item);
14415 this.select(index, false);
14420 onViewClick : function(view, doFocus, el, e)
14422 var index = this.view.getSelectedIndexes()[0];
14424 var r = this.store.getAt(index);
14428 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14435 Roo.each(this.tickItems, function(v,k){
14437 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14439 _this.tickItems.splice(k, 1);
14441 if(typeof(e) == 'undefined' && view == false){
14442 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14454 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14455 this.tickItems.push(r.data);
14458 if(typeof(e) == 'undefined' && view == false){
14459 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14466 this.onSelect(r, index);
14468 if(doFocus !== false && !this.blockFocus){
14469 this.inputEl().focus();
14474 restrictHeight : function(){
14475 //this.innerList.dom.style.height = '';
14476 //var inner = this.innerList.dom;
14477 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14478 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14479 //this.list.beginUpdate();
14480 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14481 this.list.alignTo(this.inputEl(), this.listAlign);
14482 this.list.alignTo(this.inputEl(), this.listAlign);
14483 //this.list.endUpdate();
14487 onEmptyResults : function(){
14489 if(this.tickable && this.editable){
14490 this.hasFocus = false;
14491 this.restrictHeight();
14499 * Returns true if the dropdown list is expanded, else false.
14501 isExpanded : function(){
14502 return this.list.isVisible();
14506 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14507 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14508 * @param {String} value The data value of the item to select
14509 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14510 * selected item if it is not currently in view (defaults to true)
14511 * @return {Boolean} True if the value matched an item in the list, else false
14513 selectByValue : function(v, scrollIntoView){
14514 if(v !== undefined && v !== null){
14515 var r = this.findRecord(this.valueField || this.displayField, v);
14517 this.select(this.store.indexOf(r), scrollIntoView);
14525 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14526 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14527 * @param {Number} index The zero-based index of the list item to select
14528 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14529 * selected item if it is not currently in view (defaults to true)
14531 select : function(index, scrollIntoView){
14532 this.selectedIndex = index;
14533 this.view.select(index);
14534 if(scrollIntoView !== false){
14535 var el = this.view.getNode(index);
14537 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14540 this.list.scrollChildIntoView(el, false);
14546 selectNext : function(){
14547 var ct = this.store.getCount();
14549 if(this.selectedIndex == -1){
14551 }else if(this.selectedIndex < ct-1){
14552 this.select(this.selectedIndex+1);
14558 selectPrev : function(){
14559 var ct = this.store.getCount();
14561 if(this.selectedIndex == -1){
14563 }else if(this.selectedIndex != 0){
14564 this.select(this.selectedIndex-1);
14570 onKeyUp : function(e){
14571 if(this.editable !== false && !e.isSpecialKey()){
14572 this.lastKey = e.getKey();
14573 this.dqTask.delay(this.queryDelay);
14578 validateBlur : function(){
14579 return !this.list || !this.list.isVisible();
14583 initQuery : function(){
14585 var v = this.getRawValue();
14587 if(this.tickable && this.editable){
14588 v = this.tickableInputEl().getValue();
14595 doForce : function(){
14596 if(this.inputEl().dom.value.length > 0){
14597 this.inputEl().dom.value =
14598 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14604 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14605 * query allowing the query action to be canceled if needed.
14606 * @param {String} query The SQL query to execute
14607 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14608 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14609 * saved in the current store (defaults to false)
14611 doQuery : function(q, forceAll){
14613 if(q === undefined || q === null){
14618 forceAll: forceAll,
14622 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14627 forceAll = qe.forceAll;
14628 if(forceAll === true || (q.length >= this.minChars)){
14630 this.hasQuery = true;
14632 if(this.lastQuery != q || this.alwaysQuery){
14633 this.lastQuery = q;
14634 if(this.mode == 'local'){
14635 this.selectedIndex = -1;
14637 this.store.clearFilter();
14640 if(this.specialFilter){
14641 this.fireEvent('specialfilter', this);
14646 this.store.filter(this.displayField, q);
14649 this.store.fireEvent("datachanged", this.store);
14656 this.store.baseParams[this.queryParam] = q;
14658 var options = {params : this.getParams(q)};
14661 options.add = true;
14662 options.params.start = this.page * this.pageSize;
14665 this.store.load(options);
14668 * this code will make the page width larger, at the beginning, the list not align correctly,
14669 * we should expand the list on onLoad
14670 * so command out it
14675 this.selectedIndex = -1;
14680 this.loadNext = false;
14684 getParams : function(q){
14686 //p[this.queryParam] = q;
14690 p.limit = this.pageSize;
14696 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14698 collapse : function(){
14699 if(!this.isExpanded()){
14705 this.hasFocus = false;
14709 this.cancelBtn.hide();
14710 this.trigger.show();
14713 this.tickableInputEl().dom.value = '';
14714 this.tickableInputEl().blur();
14719 Roo.get(document).un('mousedown', this.collapseIf, this);
14720 Roo.get(document).un('mousewheel', this.collapseIf, this);
14721 if (!this.editable) {
14722 Roo.get(document).un('keydown', this.listKeyPress, this);
14724 this.fireEvent('collapse', this);
14730 collapseIf : function(e){
14731 var in_combo = e.within(this.el);
14732 var in_list = e.within(this.list);
14733 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14735 if (in_combo || in_list || is_list) {
14736 //e.stopPropagation();
14741 this.onTickableFooterButtonClick(e, false, false);
14749 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14751 expand : function(){
14753 if(this.isExpanded() || !this.hasFocus){
14757 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14758 this.list.setWidth(lw);
14764 this.restrictHeight();
14768 this.tickItems = Roo.apply([], this.item);
14771 this.cancelBtn.show();
14772 this.trigger.hide();
14775 this.tickableInputEl().focus();
14780 Roo.get(document).on('mousedown', this.collapseIf, this);
14781 Roo.get(document).on('mousewheel', this.collapseIf, this);
14782 if (!this.editable) {
14783 Roo.get(document).on('keydown', this.listKeyPress, this);
14786 this.fireEvent('expand', this);
14790 // Implements the default empty TriggerField.onTriggerClick function
14791 onTriggerClick : function(e)
14793 Roo.log('trigger click');
14795 if(this.disabled || !this.triggerList){
14800 this.loadNext = false;
14802 if(this.isExpanded()){
14804 if (!this.blockFocus) {
14805 this.inputEl().focus();
14809 this.hasFocus = true;
14810 if(this.triggerAction == 'all') {
14811 this.doQuery(this.allQuery, true);
14813 this.doQuery(this.getRawValue());
14815 if (!this.blockFocus) {
14816 this.inputEl().focus();
14821 onTickableTriggerClick : function(e)
14828 this.loadNext = false;
14829 this.hasFocus = true;
14831 if(this.triggerAction == 'all') {
14832 this.doQuery(this.allQuery, true);
14834 this.doQuery(this.getRawValue());
14838 onSearchFieldClick : function(e)
14840 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14841 this.onTickableFooterButtonClick(e, false, false);
14845 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14850 this.loadNext = false;
14851 this.hasFocus = true;
14853 if(this.triggerAction == 'all') {
14854 this.doQuery(this.allQuery, true);
14856 this.doQuery(this.getRawValue());
14860 listKeyPress : function(e)
14862 //Roo.log('listkeypress');
14863 // scroll to first matching element based on key pres..
14864 if (e.isSpecialKey()) {
14867 var k = String.fromCharCode(e.getKey()).toUpperCase();
14870 var csel = this.view.getSelectedNodes();
14871 var cselitem = false;
14873 var ix = this.view.indexOf(csel[0]);
14874 cselitem = this.store.getAt(ix);
14875 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14881 this.store.each(function(v) {
14883 // start at existing selection.
14884 if (cselitem.id == v.id) {
14890 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14891 match = this.store.indexOf(v);
14897 if (match === false) {
14898 return true; // no more action?
14901 this.view.select(match);
14902 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14903 sn.scrollIntoView(sn.dom.parentNode, false);
14906 onViewScroll : function(e, t){
14908 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){
14912 this.hasQuery = true;
14914 this.loading = this.list.select('.loading', true).first();
14916 if(this.loading === null){
14917 this.list.createChild({
14919 cls: 'loading roo-select2-more-results roo-select2-active',
14920 html: 'Loading more results...'
14923 this.loading = this.list.select('.loading', true).first();
14925 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14927 this.loading.hide();
14930 this.loading.show();
14935 this.loadNext = true;
14937 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14942 addItem : function(o)
14944 var dv = ''; // display value
14946 if (this.displayField) {
14947 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14949 // this is an error condition!!!
14950 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14957 var choice = this.choices.createChild({
14959 cls: 'roo-select2-search-choice',
14968 cls: 'roo-select2-search-choice-close fa fa-times',
14973 }, this.searchField);
14975 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14977 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14985 this.inputEl().dom.value = '';
14990 onRemoveItem : function(e, _self, o)
14992 e.preventDefault();
14994 this.lastItem = Roo.apply([], this.item);
14996 var index = this.item.indexOf(o.data) * 1;
14999 Roo.log('not this item?!');
15003 this.item.splice(index, 1);
15008 this.fireEvent('remove', this, e);
15014 syncValue : function()
15016 if(!this.item.length){
15023 Roo.each(this.item, function(i){
15024 if(_this.valueField){
15025 value.push(i[_this.valueField]);
15032 this.value = value.join(',');
15034 if(this.hiddenField){
15035 this.hiddenField.dom.value = this.value;
15038 this.store.fireEvent("datachanged", this.store);
15043 clearItem : function()
15045 if(!this.multiple){
15051 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15059 if(this.tickable && !Roo.isTouch){
15060 this.view.refresh();
15064 inputEl: function ()
15066 if(Roo.isIOS && this.useNativeIOS){
15067 return this.el.select('select.roo-ios-select', true).first();
15070 if(Roo.isTouch && this.mobileTouchView){
15071 return this.el.select('input.form-control',true).first();
15075 return this.searchField;
15078 return this.el.select('input.form-control',true).first();
15081 onTickableFooterButtonClick : function(e, btn, el)
15083 e.preventDefault();
15085 this.lastItem = Roo.apply([], this.item);
15087 if(btn && btn.name == 'cancel'){
15088 this.tickItems = Roo.apply([], this.item);
15097 Roo.each(this.tickItems, function(o){
15105 validate : function()
15107 if(this.getVisibilityEl().hasClass('hidden')){
15111 var v = this.getRawValue();
15114 v = this.getValue();
15117 if(this.disabled || this.allowBlank || v.length){
15122 this.markInvalid();
15126 tickableInputEl : function()
15128 if(!this.tickable || !this.editable){
15129 return this.inputEl();
15132 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15136 getAutoCreateTouchView : function()
15141 cls: 'form-group' //input-group
15147 type : this.inputType,
15148 cls : 'form-control x-combo-noedit',
15149 autocomplete: 'new-password',
15150 placeholder : this.placeholder || '',
15155 input.name = this.name;
15159 input.cls += ' input-' + this.size;
15162 if (this.disabled) {
15163 input.disabled = true;
15174 inputblock.cls += ' input-group';
15176 inputblock.cn.unshift({
15178 cls : 'input-group-addon input-group-prepend input-group-text',
15183 if(this.removable && !this.multiple){
15184 inputblock.cls += ' roo-removable';
15186 inputblock.cn.push({
15189 cls : 'roo-combo-removable-btn close'
15193 if(this.hasFeedback && !this.allowBlank){
15195 inputblock.cls += ' has-feedback';
15197 inputblock.cn.push({
15199 cls: 'glyphicon form-control-feedback'
15206 inputblock.cls += (this.before) ? '' : ' input-group';
15208 inputblock.cn.push({
15210 cls : 'input-group-addon input-group-append input-group-text',
15216 var ibwrap = inputblock;
15221 cls: 'roo-select2-choices',
15225 cls: 'roo-select2-search-field',
15238 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15243 cls: 'form-hidden-field'
15249 if(!this.multiple && this.showToggleBtn){
15256 if (this.caret != false) {
15259 cls: 'fa fa-' + this.caret
15266 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15271 cls: 'combobox-clear',
15285 combobox.cls += ' roo-select2-container-multi';
15288 var align = this.labelAlign || this.parentLabelAlign();
15290 if (align ==='left' && this.fieldLabel.length) {
15295 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15296 tooltip : 'This field is required'
15300 cls : 'control-label col-form-label',
15301 html : this.fieldLabel
15312 var labelCfg = cfg.cn[1];
15313 var contentCfg = cfg.cn[2];
15316 if(this.indicatorpos == 'right'){
15321 cls : 'control-label col-form-label',
15325 html : this.fieldLabel
15329 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15330 tooltip : 'This field is required'
15343 labelCfg = cfg.cn[0];
15344 contentCfg = cfg.cn[1];
15349 if(this.labelWidth > 12){
15350 labelCfg.style = "width: " + this.labelWidth + 'px';
15353 if(this.labelWidth < 13 && this.labelmd == 0){
15354 this.labelmd = this.labelWidth;
15357 if(this.labellg > 0){
15358 labelCfg.cls += ' col-lg-' + this.labellg;
15359 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15362 if(this.labelmd > 0){
15363 labelCfg.cls += ' col-md-' + this.labelmd;
15364 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15367 if(this.labelsm > 0){
15368 labelCfg.cls += ' col-sm-' + this.labelsm;
15369 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15372 if(this.labelxs > 0){
15373 labelCfg.cls += ' col-xs-' + this.labelxs;
15374 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15378 } else if ( this.fieldLabel.length) {
15382 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15383 tooltip : 'This field is required'
15387 cls : 'control-label',
15388 html : this.fieldLabel
15399 if(this.indicatorpos == 'right'){
15403 cls : 'control-label',
15404 html : this.fieldLabel,
15408 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15409 tooltip : 'This field is required'
15426 var settings = this;
15428 ['xs','sm','md','lg'].map(function(size){
15429 if (settings[size]) {
15430 cfg.cls += ' col-' + size + '-' + settings[size];
15437 initTouchView : function()
15439 this.renderTouchView();
15441 this.touchViewEl.on('scroll', function(){
15442 this.el.dom.scrollTop = 0;
15445 this.originalValue = this.getValue();
15447 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15449 this.inputEl().on("click", this.showTouchView, this);
15450 if (this.triggerEl) {
15451 this.triggerEl.on("click", this.showTouchView, this);
15455 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15456 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15458 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15460 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15461 this.store.on('load', this.onTouchViewLoad, this);
15462 this.store.on('loadexception', this.onTouchViewLoadException, this);
15464 if(this.hiddenName){
15466 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15468 this.hiddenField.dom.value =
15469 this.hiddenValue !== undefined ? this.hiddenValue :
15470 this.value !== undefined ? this.value : '';
15472 this.el.dom.removeAttribute('name');
15473 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15477 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15478 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15481 if(this.removable && !this.multiple){
15482 var close = this.closeTriggerEl();
15484 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15485 close.on('click', this.removeBtnClick, this, close);
15489 * fix the bug in Safari iOS8
15491 this.inputEl().on("focus", function(e){
15492 document.activeElement.blur();
15495 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15502 renderTouchView : function()
15504 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15505 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15507 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15508 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15510 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15511 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15512 this.touchViewBodyEl.setStyle('overflow', 'auto');
15514 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15515 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15517 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15518 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15522 showTouchView : function()
15528 this.touchViewHeaderEl.hide();
15530 if(this.modalTitle.length){
15531 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15532 this.touchViewHeaderEl.show();
15535 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15536 this.touchViewEl.show();
15538 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15540 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15541 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15543 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15545 if(this.modalTitle.length){
15546 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15549 this.touchViewBodyEl.setHeight(bodyHeight);
15553 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15555 this.touchViewEl.addClass('in');
15558 if(this._touchViewMask){
15559 Roo.get(document.body).addClass("x-body-masked");
15560 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15561 this._touchViewMask.setStyle('z-index', 10000);
15562 this._touchViewMask.addClass('show');
15565 this.doTouchViewQuery();
15569 hideTouchView : function()
15571 this.touchViewEl.removeClass('in');
15575 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15577 this.touchViewEl.setStyle('display', 'none');
15580 if(this._touchViewMask){
15581 this._touchViewMask.removeClass('show');
15582 Roo.get(document.body).removeClass("x-body-masked");
15586 setTouchViewValue : function()
15593 Roo.each(this.tickItems, function(o){
15598 this.hideTouchView();
15601 doTouchViewQuery : function()
15610 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15614 if(!this.alwaysQuery || this.mode == 'local'){
15615 this.onTouchViewLoad();
15622 onTouchViewBeforeLoad : function(combo,opts)
15628 onTouchViewLoad : function()
15630 if(this.store.getCount() < 1){
15631 this.onTouchViewEmptyResults();
15635 this.clearTouchView();
15637 var rawValue = this.getRawValue();
15639 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15641 this.tickItems = [];
15643 this.store.data.each(function(d, rowIndex){
15644 var row = this.touchViewListGroup.createChild(template);
15646 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15647 row.addClass(d.data.cls);
15650 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15653 html : d.data[this.displayField]
15656 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15657 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15660 row.removeClass('selected');
15661 if(!this.multiple && this.valueField &&
15662 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15665 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15666 row.addClass('selected');
15669 if(this.multiple && this.valueField &&
15670 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15674 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15675 this.tickItems.push(d.data);
15678 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15682 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15684 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15686 if(this.modalTitle.length){
15687 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15690 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15692 if(this.mobile_restrict_height && listHeight < bodyHeight){
15693 this.touchViewBodyEl.setHeight(listHeight);
15698 if(firstChecked && listHeight > bodyHeight){
15699 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15704 onTouchViewLoadException : function()
15706 this.hideTouchView();
15709 onTouchViewEmptyResults : function()
15711 this.clearTouchView();
15713 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15715 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15719 clearTouchView : function()
15721 this.touchViewListGroup.dom.innerHTML = '';
15724 onTouchViewClick : function(e, el, o)
15726 e.preventDefault();
15729 var rowIndex = o.rowIndex;
15731 var r = this.store.getAt(rowIndex);
15733 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15735 if(!this.multiple){
15736 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15737 c.dom.removeAttribute('checked');
15740 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15742 this.setFromData(r.data);
15744 var close = this.closeTriggerEl();
15750 this.hideTouchView();
15752 this.fireEvent('select', this, r, rowIndex);
15757 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15758 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15759 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15763 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15764 this.addItem(r.data);
15765 this.tickItems.push(r.data);
15769 getAutoCreateNativeIOS : function()
15772 cls: 'form-group' //input-group,
15777 cls : 'roo-ios-select'
15781 combobox.name = this.name;
15784 if (this.disabled) {
15785 combobox.disabled = true;
15788 var settings = this;
15790 ['xs','sm','md','lg'].map(function(size){
15791 if (settings[size]) {
15792 cfg.cls += ' col-' + size + '-' + settings[size];
15802 initIOSView : function()
15804 this.store.on('load', this.onIOSViewLoad, this);
15809 onIOSViewLoad : function()
15811 if(this.store.getCount() < 1){
15815 this.clearIOSView();
15817 if(this.allowBlank) {
15819 var default_text = '-- SELECT --';
15821 if(this.placeholder.length){
15822 default_text = this.placeholder;
15825 if(this.emptyTitle.length){
15826 default_text += ' - ' + this.emptyTitle + ' -';
15829 var opt = this.inputEl().createChild({
15832 html : default_text
15836 o[this.valueField] = 0;
15837 o[this.displayField] = default_text;
15839 this.ios_options.push({
15846 this.store.data.each(function(d, rowIndex){
15850 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15851 html = d.data[this.displayField];
15856 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15857 value = d.data[this.valueField];
15866 if(this.value == d.data[this.valueField]){
15867 option['selected'] = true;
15870 var opt = this.inputEl().createChild(option);
15872 this.ios_options.push({
15879 this.inputEl().on('change', function(){
15880 this.fireEvent('select', this);
15885 clearIOSView: function()
15887 this.inputEl().dom.innerHTML = '';
15889 this.ios_options = [];
15892 setIOSValue: function(v)
15896 if(!this.ios_options){
15900 Roo.each(this.ios_options, function(opts){
15902 opts.el.dom.removeAttribute('selected');
15904 if(opts.data[this.valueField] != v){
15908 opts.el.dom.setAttribute('selected', true);
15914 * @cfg {Boolean} grow
15918 * @cfg {Number} growMin
15922 * @cfg {Number} growMax
15931 Roo.apply(Roo.bootstrap.ComboBox, {
15935 cls: 'modal-header',
15957 cls: 'list-group-item',
15961 cls: 'roo-combobox-list-group-item-value'
15965 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15979 listItemCheckbox : {
15981 cls: 'list-group-item',
15985 cls: 'roo-combobox-list-group-item-value'
15989 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16005 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16010 cls: 'modal-footer',
16018 cls: 'col-xs-6 text-left',
16021 cls: 'btn btn-danger roo-touch-view-cancel',
16027 cls: 'col-xs-6 text-right',
16030 cls: 'btn btn-success roo-touch-view-ok',
16041 Roo.apply(Roo.bootstrap.ComboBox, {
16043 touchViewTemplate : {
16045 cls: 'modal fade roo-combobox-touch-view',
16049 cls: 'modal-dialog',
16050 style : 'position:fixed', // we have to fix position....
16054 cls: 'modal-content',
16056 Roo.bootstrap.ComboBox.header,
16057 Roo.bootstrap.ComboBox.body,
16058 Roo.bootstrap.ComboBox.footer
16067 * Ext JS Library 1.1.1
16068 * Copyright(c) 2006-2007, Ext JS, LLC.
16070 * Originally Released Under LGPL - original licence link has changed is not relivant.
16073 * <script type="text/javascript">
16078 * @extends Roo.util.Observable
16079 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16080 * This class also supports single and multi selection modes. <br>
16081 * Create a data model bound view:
16083 var store = new Roo.data.Store(...);
16085 var view = new Roo.View({
16087 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16089 singleSelect: true,
16090 selectedClass: "ydataview-selected",
16094 // listen for node click?
16095 view.on("click", function(vw, index, node, e){
16096 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16100 dataModel.load("foobar.xml");
16102 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16104 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16105 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16107 * Note: old style constructor is still suported (container, template, config)
16110 * Create a new View
16111 * @param {Object} config The config object
16114 Roo.View = function(config, depreciated_tpl, depreciated_config){
16116 this.parent = false;
16118 if (typeof(depreciated_tpl) == 'undefined') {
16119 // new way.. - universal constructor.
16120 Roo.apply(this, config);
16121 this.el = Roo.get(this.el);
16124 this.el = Roo.get(config);
16125 this.tpl = depreciated_tpl;
16126 Roo.apply(this, depreciated_config);
16128 this.wrapEl = this.el.wrap().wrap();
16129 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16132 if(typeof(this.tpl) == "string"){
16133 this.tpl = new Roo.Template(this.tpl);
16135 // support xtype ctors..
16136 this.tpl = new Roo.factory(this.tpl, Roo);
16140 this.tpl.compile();
16145 * @event beforeclick
16146 * Fires before a click is processed. Returns false to cancel the default action.
16147 * @param {Roo.View} this
16148 * @param {Number} index The index of the target node
16149 * @param {HTMLElement} node The target node
16150 * @param {Roo.EventObject} e The raw event object
16152 "beforeclick" : true,
16155 * Fires when a template node is clicked.
16156 * @param {Roo.View} this
16157 * @param {Number} index The index of the target node
16158 * @param {HTMLElement} node The target node
16159 * @param {Roo.EventObject} e The raw event object
16164 * Fires when a template node is double clicked.
16165 * @param {Roo.View} this
16166 * @param {Number} index The index of the target node
16167 * @param {HTMLElement} node The target node
16168 * @param {Roo.EventObject} e The raw event object
16172 * @event contextmenu
16173 * Fires when a template node is right clicked.
16174 * @param {Roo.View} this
16175 * @param {Number} index The index of the target node
16176 * @param {HTMLElement} node The target node
16177 * @param {Roo.EventObject} e The raw event object
16179 "contextmenu" : true,
16181 * @event selectionchange
16182 * Fires when the selected nodes change.
16183 * @param {Roo.View} this
16184 * @param {Array} selections Array of the selected nodes
16186 "selectionchange" : true,
16189 * @event beforeselect
16190 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16191 * @param {Roo.View} this
16192 * @param {HTMLElement} node The node to be selected
16193 * @param {Array} selections Array of currently selected nodes
16195 "beforeselect" : true,
16197 * @event preparedata
16198 * Fires on every row to render, to allow you to change the data.
16199 * @param {Roo.View} this
16200 * @param {Object} data to be rendered (change this)
16202 "preparedata" : true
16210 "click": this.onClick,
16211 "dblclick": this.onDblClick,
16212 "contextmenu": this.onContextMenu,
16216 this.selections = [];
16218 this.cmp = new Roo.CompositeElementLite([]);
16220 this.store = Roo.factory(this.store, Roo.data);
16221 this.setStore(this.store, true);
16224 if ( this.footer && this.footer.xtype) {
16226 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16228 this.footer.dataSource = this.store;
16229 this.footer.container = fctr;
16230 this.footer = Roo.factory(this.footer, Roo);
16231 fctr.insertFirst(this.el);
16233 // this is a bit insane - as the paging toolbar seems to detach the el..
16234 // dom.parentNode.parentNode.parentNode
16235 // they get detached?
16239 Roo.View.superclass.constructor.call(this);
16244 Roo.extend(Roo.View, Roo.util.Observable, {
16247 * @cfg {Roo.data.Store} store Data store to load data from.
16252 * @cfg {String|Roo.Element} el The container element.
16257 * @cfg {String|Roo.Template} tpl The template used by this View
16261 * @cfg {String} dataName the named area of the template to use as the data area
16262 * Works with domtemplates roo-name="name"
16266 * @cfg {String} selectedClass The css class to add to selected nodes
16268 selectedClass : "x-view-selected",
16270 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16275 * @cfg {String} text to display on mask (default Loading)
16279 * @cfg {Boolean} multiSelect Allow multiple selection
16281 multiSelect : false,
16283 * @cfg {Boolean} singleSelect Allow single selection
16285 singleSelect: false,
16288 * @cfg {Boolean} toggleSelect - selecting
16290 toggleSelect : false,
16293 * @cfg {Boolean} tickable - selecting
16298 * Returns the element this view is bound to.
16299 * @return {Roo.Element}
16301 getEl : function(){
16302 return this.wrapEl;
16308 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16310 refresh : function(){
16311 //Roo.log('refresh');
16314 // if we are using something like 'domtemplate', then
16315 // the what gets used is:
16316 // t.applySubtemplate(NAME, data, wrapping data..)
16317 // the outer template then get' applied with
16318 // the store 'extra data'
16319 // and the body get's added to the
16320 // roo-name="data" node?
16321 // <span class='roo-tpl-{name}'></span> ?????
16325 this.clearSelections();
16326 this.el.update("");
16328 var records = this.store.getRange();
16329 if(records.length < 1) {
16331 // is this valid?? = should it render a template??
16333 this.el.update(this.emptyText);
16337 if (this.dataName) {
16338 this.el.update(t.apply(this.store.meta)); //????
16339 el = this.el.child('.roo-tpl-' + this.dataName);
16342 for(var i = 0, len = records.length; i < len; i++){
16343 var data = this.prepareData(records[i].data, i, records[i]);
16344 this.fireEvent("preparedata", this, data, i, records[i]);
16346 var d = Roo.apply({}, data);
16349 Roo.apply(d, {'roo-id' : Roo.id()});
16353 Roo.each(this.parent.item, function(item){
16354 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16357 Roo.apply(d, {'roo-data-checked' : 'checked'});
16361 html[html.length] = Roo.util.Format.trim(
16363 t.applySubtemplate(this.dataName, d, this.store.meta) :
16370 el.update(html.join(""));
16371 this.nodes = el.dom.childNodes;
16372 this.updateIndexes(0);
16377 * Function to override to reformat the data that is sent to
16378 * the template for each node.
16379 * DEPRICATED - use the preparedata event handler.
16380 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16381 * a JSON object for an UpdateManager bound view).
16383 prepareData : function(data, index, record)
16385 this.fireEvent("preparedata", this, data, index, record);
16389 onUpdate : function(ds, record){
16390 // Roo.log('on update');
16391 this.clearSelections();
16392 var index = this.store.indexOf(record);
16393 var n = this.nodes[index];
16394 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16395 n.parentNode.removeChild(n);
16396 this.updateIndexes(index, index);
16402 onAdd : function(ds, records, index)
16404 //Roo.log(['on Add', ds, records, index] );
16405 this.clearSelections();
16406 if(this.nodes.length == 0){
16410 var n = this.nodes[index];
16411 for(var i = 0, len = records.length; i < len; i++){
16412 var d = this.prepareData(records[i].data, i, records[i]);
16414 this.tpl.insertBefore(n, d);
16417 this.tpl.append(this.el, d);
16420 this.updateIndexes(index);
16423 onRemove : function(ds, record, index){
16424 // Roo.log('onRemove');
16425 this.clearSelections();
16426 var el = this.dataName ?
16427 this.el.child('.roo-tpl-' + this.dataName) :
16430 el.dom.removeChild(this.nodes[index]);
16431 this.updateIndexes(index);
16435 * Refresh an individual node.
16436 * @param {Number} index
16438 refreshNode : function(index){
16439 this.onUpdate(this.store, this.store.getAt(index));
16442 updateIndexes : function(startIndex, endIndex){
16443 var ns = this.nodes;
16444 startIndex = startIndex || 0;
16445 endIndex = endIndex || ns.length - 1;
16446 for(var i = startIndex; i <= endIndex; i++){
16447 ns[i].nodeIndex = i;
16452 * Changes the data store this view uses and refresh the view.
16453 * @param {Store} store
16455 setStore : function(store, initial){
16456 if(!initial && this.store){
16457 this.store.un("datachanged", this.refresh);
16458 this.store.un("add", this.onAdd);
16459 this.store.un("remove", this.onRemove);
16460 this.store.un("update", this.onUpdate);
16461 this.store.un("clear", this.refresh);
16462 this.store.un("beforeload", this.onBeforeLoad);
16463 this.store.un("load", this.onLoad);
16464 this.store.un("loadexception", this.onLoad);
16468 store.on("datachanged", this.refresh, this);
16469 store.on("add", this.onAdd, this);
16470 store.on("remove", this.onRemove, this);
16471 store.on("update", this.onUpdate, this);
16472 store.on("clear", this.refresh, this);
16473 store.on("beforeload", this.onBeforeLoad, this);
16474 store.on("load", this.onLoad, this);
16475 store.on("loadexception", this.onLoad, this);
16483 * onbeforeLoad - masks the loading area.
16486 onBeforeLoad : function(store,opts)
16488 //Roo.log('onBeforeLoad');
16490 this.el.update("");
16492 this.el.mask(this.mask ? this.mask : "Loading" );
16494 onLoad : function ()
16501 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16502 * @param {HTMLElement} node
16503 * @return {HTMLElement} The template node
16505 findItemFromChild : function(node){
16506 var el = this.dataName ?
16507 this.el.child('.roo-tpl-' + this.dataName,true) :
16510 if(!node || node.parentNode == el){
16513 var p = node.parentNode;
16514 while(p && p != el){
16515 if(p.parentNode == el){
16524 onClick : function(e){
16525 var item = this.findItemFromChild(e.getTarget());
16527 var index = this.indexOf(item);
16528 if(this.onItemClick(item, index, e) !== false){
16529 this.fireEvent("click", this, index, item, e);
16532 this.clearSelections();
16537 onContextMenu : function(e){
16538 var item = this.findItemFromChild(e.getTarget());
16540 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16545 onDblClick : function(e){
16546 var item = this.findItemFromChild(e.getTarget());
16548 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16552 onItemClick : function(item, index, e)
16554 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16557 if (this.toggleSelect) {
16558 var m = this.isSelected(item) ? 'unselect' : 'select';
16561 _t[m](item, true, false);
16564 if(this.multiSelect || this.singleSelect){
16565 if(this.multiSelect && e.shiftKey && this.lastSelection){
16566 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16568 this.select(item, this.multiSelect && e.ctrlKey);
16569 this.lastSelection = item;
16572 if(!this.tickable){
16573 e.preventDefault();
16581 * Get the number of selected nodes.
16584 getSelectionCount : function(){
16585 return this.selections.length;
16589 * Get the currently selected nodes.
16590 * @return {Array} An array of HTMLElements
16592 getSelectedNodes : function(){
16593 return this.selections;
16597 * Get the indexes of the selected nodes.
16600 getSelectedIndexes : function(){
16601 var indexes = [], s = this.selections;
16602 for(var i = 0, len = s.length; i < len; i++){
16603 indexes.push(s[i].nodeIndex);
16609 * Clear all selections
16610 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16612 clearSelections : function(suppressEvent){
16613 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16614 this.cmp.elements = this.selections;
16615 this.cmp.removeClass(this.selectedClass);
16616 this.selections = [];
16617 if(!suppressEvent){
16618 this.fireEvent("selectionchange", this, this.selections);
16624 * Returns true if the passed node is selected
16625 * @param {HTMLElement/Number} node The node or node index
16626 * @return {Boolean}
16628 isSelected : function(node){
16629 var s = this.selections;
16633 node = this.getNode(node);
16634 return s.indexOf(node) !== -1;
16639 * @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
16640 * @param {Boolean} keepExisting (optional) true to keep existing selections
16641 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16643 select : function(nodeInfo, keepExisting, suppressEvent){
16644 if(nodeInfo instanceof Array){
16646 this.clearSelections(true);
16648 for(var i = 0, len = nodeInfo.length; i < len; i++){
16649 this.select(nodeInfo[i], true, true);
16653 var node = this.getNode(nodeInfo);
16654 if(!node || this.isSelected(node)){
16655 return; // already selected.
16658 this.clearSelections(true);
16661 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16662 Roo.fly(node).addClass(this.selectedClass);
16663 this.selections.push(node);
16664 if(!suppressEvent){
16665 this.fireEvent("selectionchange", this, this.selections);
16673 * @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
16674 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16675 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16677 unselect : function(nodeInfo, keepExisting, suppressEvent)
16679 if(nodeInfo instanceof Array){
16680 Roo.each(this.selections, function(s) {
16681 this.unselect(s, nodeInfo);
16685 var node = this.getNode(nodeInfo);
16686 if(!node || !this.isSelected(node)){
16687 //Roo.log("not selected");
16688 return; // not selected.
16692 Roo.each(this.selections, function(s) {
16694 Roo.fly(node).removeClass(this.selectedClass);
16701 this.selections= ns;
16702 this.fireEvent("selectionchange", this, this.selections);
16706 * Gets a template node.
16707 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16708 * @return {HTMLElement} The node or null if it wasn't found
16710 getNode : function(nodeInfo){
16711 if(typeof nodeInfo == "string"){
16712 return document.getElementById(nodeInfo);
16713 }else if(typeof nodeInfo == "number"){
16714 return this.nodes[nodeInfo];
16720 * Gets a range template nodes.
16721 * @param {Number} startIndex
16722 * @param {Number} endIndex
16723 * @return {Array} An array of nodes
16725 getNodes : function(start, end){
16726 var ns = this.nodes;
16727 start = start || 0;
16728 end = typeof end == "undefined" ? ns.length - 1 : end;
16731 for(var i = start; i <= end; i++){
16735 for(var i = start; i >= end; i--){
16743 * Finds the index of the passed node
16744 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16745 * @return {Number} The index of the node or -1
16747 indexOf : function(node){
16748 node = this.getNode(node);
16749 if(typeof node.nodeIndex == "number"){
16750 return node.nodeIndex;
16752 var ns = this.nodes;
16753 for(var i = 0, len = ns.length; i < len; i++){
16764 * based on jquery fullcalendar
16768 Roo.bootstrap = Roo.bootstrap || {};
16770 * @class Roo.bootstrap.Calendar
16771 * @extends Roo.bootstrap.Component
16772 * Bootstrap Calendar class
16773 * @cfg {Boolean} loadMask (true|false) default false
16774 * @cfg {Object} header generate the user specific header of the calendar, default false
16777 * Create a new Container
16778 * @param {Object} config The config object
16783 Roo.bootstrap.Calendar = function(config){
16784 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16788 * Fires when a date is selected
16789 * @param {DatePicker} this
16790 * @param {Date} date The selected date
16794 * @event monthchange
16795 * Fires when the displayed month changes
16796 * @param {DatePicker} this
16797 * @param {Date} date The selected month
16799 'monthchange': true,
16801 * @event evententer
16802 * Fires when mouse over an event
16803 * @param {Calendar} this
16804 * @param {event} Event
16806 'evententer': true,
16808 * @event eventleave
16809 * Fires when the mouse leaves an
16810 * @param {Calendar} this
16813 'eventleave': true,
16815 * @event eventclick
16816 * Fires when the mouse click an
16817 * @param {Calendar} this
16826 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16829 * @cfg {Number} startDay
16830 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16838 getAutoCreate : function(){
16841 var fc_button = function(name, corner, style, content ) {
16842 return Roo.apply({},{
16844 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16846 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16849 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16860 style : 'width:100%',
16867 cls : 'fc-header-left',
16869 fc_button('prev', 'left', 'arrow', '‹' ),
16870 fc_button('next', 'right', 'arrow', '›' ),
16871 { tag: 'span', cls: 'fc-header-space' },
16872 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16880 cls : 'fc-header-center',
16884 cls: 'fc-header-title',
16887 html : 'month / year'
16895 cls : 'fc-header-right',
16897 /* fc_button('month', 'left', '', 'month' ),
16898 fc_button('week', '', '', 'week' ),
16899 fc_button('day', 'right', '', 'day' )
16911 header = this.header;
16914 var cal_heads = function() {
16916 // fixme - handle this.
16918 for (var i =0; i < Date.dayNames.length; i++) {
16919 var d = Date.dayNames[i];
16922 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16923 html : d.substring(0,3)
16927 ret[0].cls += ' fc-first';
16928 ret[6].cls += ' fc-last';
16931 var cal_cell = function(n) {
16934 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16939 cls: 'fc-day-number',
16943 cls: 'fc-day-content',
16947 style: 'position: relative;' // height: 17px;
16959 var cal_rows = function() {
16962 for (var r = 0; r < 6; r++) {
16969 for (var i =0; i < Date.dayNames.length; i++) {
16970 var d = Date.dayNames[i];
16971 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16974 row.cn[0].cls+=' fc-first';
16975 row.cn[0].cn[0].style = 'min-height:90px';
16976 row.cn[6].cls+=' fc-last';
16980 ret[0].cls += ' fc-first';
16981 ret[4].cls += ' fc-prev-last';
16982 ret[5].cls += ' fc-last';
16989 cls: 'fc-border-separate',
16990 style : 'width:100%',
16998 cls : 'fc-first fc-last',
17016 cls : 'fc-content',
17017 style : "position: relative;",
17020 cls : 'fc-view fc-view-month fc-grid',
17021 style : 'position: relative',
17022 unselectable : 'on',
17025 cls : 'fc-event-container',
17026 style : 'position:absolute;z-index:8;top:0;left:0;'
17044 initEvents : function()
17047 throw "can not find store for calendar";
17053 style: "text-align:center",
17057 style: "background-color:white;width:50%;margin:250 auto",
17061 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17072 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17074 var size = this.el.select('.fc-content', true).first().getSize();
17075 this.maskEl.setSize(size.width, size.height);
17076 this.maskEl.enableDisplayMode("block");
17077 if(!this.loadMask){
17078 this.maskEl.hide();
17081 this.store = Roo.factory(this.store, Roo.data);
17082 this.store.on('load', this.onLoad, this);
17083 this.store.on('beforeload', this.onBeforeLoad, this);
17087 this.cells = this.el.select('.fc-day',true);
17088 //Roo.log(this.cells);
17089 this.textNodes = this.el.query('.fc-day-number');
17090 this.cells.addClassOnOver('fc-state-hover');
17092 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17093 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17094 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17095 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17097 this.on('monthchange', this.onMonthChange, this);
17099 this.update(new Date().clearTime());
17102 resize : function() {
17103 var sz = this.el.getSize();
17105 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17106 this.el.select('.fc-day-content div',true).setHeight(34);
17111 showPrevMonth : function(e){
17112 this.update(this.activeDate.add("mo", -1));
17114 showToday : function(e){
17115 this.update(new Date().clearTime());
17118 showNextMonth : function(e){
17119 this.update(this.activeDate.add("mo", 1));
17123 showPrevYear : function(){
17124 this.update(this.activeDate.add("y", -1));
17128 showNextYear : function(){
17129 this.update(this.activeDate.add("y", 1));
17134 update : function(date)
17136 var vd = this.activeDate;
17137 this.activeDate = date;
17138 // if(vd && this.el){
17139 // var t = date.getTime();
17140 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17141 // Roo.log('using add remove');
17143 // this.fireEvent('monthchange', this, date);
17145 // this.cells.removeClass("fc-state-highlight");
17146 // this.cells.each(function(c){
17147 // if(c.dateValue == t){
17148 // c.addClass("fc-state-highlight");
17149 // setTimeout(function(){
17150 // try{c.dom.firstChild.focus();}catch(e){}
17160 var days = date.getDaysInMonth();
17162 var firstOfMonth = date.getFirstDateOfMonth();
17163 var startingPos = firstOfMonth.getDay()-this.startDay;
17165 if(startingPos < this.startDay){
17169 var pm = date.add(Date.MONTH, -1);
17170 var prevStart = pm.getDaysInMonth()-startingPos;
17172 this.cells = this.el.select('.fc-day',true);
17173 this.textNodes = this.el.query('.fc-day-number');
17174 this.cells.addClassOnOver('fc-state-hover');
17176 var cells = this.cells.elements;
17177 var textEls = this.textNodes;
17179 Roo.each(cells, function(cell){
17180 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17183 days += startingPos;
17185 // convert everything to numbers so it's fast
17186 var day = 86400000;
17187 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17190 //Roo.log(prevStart);
17192 var today = new Date().clearTime().getTime();
17193 var sel = date.clearTime().getTime();
17194 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17195 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17196 var ddMatch = this.disabledDatesRE;
17197 var ddText = this.disabledDatesText;
17198 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17199 var ddaysText = this.disabledDaysText;
17200 var format = this.format;
17202 var setCellClass = function(cal, cell){
17206 //Roo.log('set Cell Class');
17208 var t = d.getTime();
17212 cell.dateValue = t;
17214 cell.className += " fc-today";
17215 cell.className += " fc-state-highlight";
17216 cell.title = cal.todayText;
17219 // disable highlight in other month..
17220 //cell.className += " fc-state-highlight";
17225 cell.className = " fc-state-disabled";
17226 cell.title = cal.minText;
17230 cell.className = " fc-state-disabled";
17231 cell.title = cal.maxText;
17235 if(ddays.indexOf(d.getDay()) != -1){
17236 cell.title = ddaysText;
17237 cell.className = " fc-state-disabled";
17240 if(ddMatch && format){
17241 var fvalue = d.dateFormat(format);
17242 if(ddMatch.test(fvalue)){
17243 cell.title = ddText.replace("%0", fvalue);
17244 cell.className = " fc-state-disabled";
17248 if (!cell.initialClassName) {
17249 cell.initialClassName = cell.dom.className;
17252 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17257 for(; i < startingPos; i++) {
17258 textEls[i].innerHTML = (++prevStart);
17259 d.setDate(d.getDate()+1);
17261 cells[i].className = "fc-past fc-other-month";
17262 setCellClass(this, cells[i]);
17267 for(; i < days; i++){
17268 intDay = i - startingPos + 1;
17269 textEls[i].innerHTML = (intDay);
17270 d.setDate(d.getDate()+1);
17272 cells[i].className = ''; // "x-date-active";
17273 setCellClass(this, cells[i]);
17277 for(; i < 42; i++) {
17278 textEls[i].innerHTML = (++extraDays);
17279 d.setDate(d.getDate()+1);
17281 cells[i].className = "fc-future fc-other-month";
17282 setCellClass(this, cells[i]);
17285 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17287 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17289 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17290 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17292 if(totalRows != 6){
17293 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17294 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17297 this.fireEvent('monthchange', this, date);
17301 if(!this.internalRender){
17302 var main = this.el.dom.firstChild;
17303 var w = main.offsetWidth;
17304 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17305 Roo.fly(main).setWidth(w);
17306 this.internalRender = true;
17307 // opera does not respect the auto grow header center column
17308 // then, after it gets a width opera refuses to recalculate
17309 // without a second pass
17310 if(Roo.isOpera && !this.secondPass){
17311 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17312 this.secondPass = true;
17313 this.update.defer(10, this, [date]);
17320 findCell : function(dt) {
17321 dt = dt.clearTime().getTime();
17323 this.cells.each(function(c){
17324 //Roo.log("check " +c.dateValue + '?=' + dt);
17325 if(c.dateValue == dt){
17335 findCells : function(ev) {
17336 var s = ev.start.clone().clearTime().getTime();
17338 var e= ev.end.clone().clearTime().getTime();
17341 this.cells.each(function(c){
17342 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17344 if(c.dateValue > e){
17347 if(c.dateValue < s){
17356 // findBestRow: function(cells)
17360 // for (var i =0 ; i < cells.length;i++) {
17361 // ret = Math.max(cells[i].rows || 0,ret);
17368 addItem : function(ev)
17370 // look for vertical location slot in
17371 var cells = this.findCells(ev);
17373 // ev.row = this.findBestRow(cells);
17375 // work out the location.
17379 for(var i =0; i < cells.length; i++) {
17381 cells[i].row = cells[0].row;
17384 cells[i].row = cells[i].row + 1;
17394 if (crow.start.getY() == cells[i].getY()) {
17396 crow.end = cells[i];
17413 cells[0].events.push(ev);
17415 this.calevents.push(ev);
17418 clearEvents: function() {
17420 if(!this.calevents){
17424 Roo.each(this.cells.elements, function(c){
17430 Roo.each(this.calevents, function(e) {
17431 Roo.each(e.els, function(el) {
17432 el.un('mouseenter' ,this.onEventEnter, this);
17433 el.un('mouseleave' ,this.onEventLeave, this);
17438 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17444 renderEvents: function()
17448 this.cells.each(function(c) {
17457 if(c.row != c.events.length){
17458 r = 4 - (4 - (c.row - c.events.length));
17461 c.events = ev.slice(0, r);
17462 c.more = ev.slice(r);
17464 if(c.more.length && c.more.length == 1){
17465 c.events.push(c.more.pop());
17468 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17472 this.cells.each(function(c) {
17474 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17477 for (var e = 0; e < c.events.length; e++){
17478 var ev = c.events[e];
17479 var rows = ev.rows;
17481 for(var i = 0; i < rows.length; i++) {
17483 // how many rows should it span..
17486 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17487 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17489 unselectable : "on",
17492 cls: 'fc-event-inner',
17496 // cls: 'fc-event-time',
17497 // html : cells.length > 1 ? '' : ev.time
17501 cls: 'fc-event-title',
17502 html : String.format('{0}', ev.title)
17509 cls: 'ui-resizable-handle ui-resizable-e',
17510 html : '  '
17517 cfg.cls += ' fc-event-start';
17519 if ((i+1) == rows.length) {
17520 cfg.cls += ' fc-event-end';
17523 var ctr = _this.el.select('.fc-event-container',true).first();
17524 var cg = ctr.createChild(cfg);
17526 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17527 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17529 var r = (c.more.length) ? 1 : 0;
17530 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17531 cg.setWidth(ebox.right - sbox.x -2);
17533 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17534 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17535 cg.on('click', _this.onEventClick, _this, ev);
17546 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17547 style : 'position: absolute',
17548 unselectable : "on",
17551 cls: 'fc-event-inner',
17555 cls: 'fc-event-title',
17563 cls: 'ui-resizable-handle ui-resizable-e',
17564 html : '  '
17570 var ctr = _this.el.select('.fc-event-container',true).first();
17571 var cg = ctr.createChild(cfg);
17573 var sbox = c.select('.fc-day-content',true).first().getBox();
17574 var ebox = c.select('.fc-day-content',true).first().getBox();
17576 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17577 cg.setWidth(ebox.right - sbox.x -2);
17579 cg.on('click', _this.onMoreEventClick, _this, c.more);
17589 onEventEnter: function (e, el,event,d) {
17590 this.fireEvent('evententer', this, el, event);
17593 onEventLeave: function (e, el,event,d) {
17594 this.fireEvent('eventleave', this, el, event);
17597 onEventClick: function (e, el,event,d) {
17598 this.fireEvent('eventclick', this, el, event);
17601 onMonthChange: function () {
17605 onMoreEventClick: function(e, el, more)
17609 this.calpopover.placement = 'right';
17610 this.calpopover.setTitle('More');
17612 this.calpopover.setContent('');
17614 var ctr = this.calpopover.el.select('.popover-content', true).first();
17616 Roo.each(more, function(m){
17618 cls : 'fc-event-hori fc-event-draggable',
17621 var cg = ctr.createChild(cfg);
17623 cg.on('click', _this.onEventClick, _this, m);
17626 this.calpopover.show(el);
17631 onLoad: function ()
17633 this.calevents = [];
17636 if(this.store.getCount() > 0){
17637 this.store.data.each(function(d){
17640 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17641 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17642 time : d.data.start_time,
17643 title : d.data.title,
17644 description : d.data.description,
17645 venue : d.data.venue
17650 this.renderEvents();
17652 if(this.calevents.length && this.loadMask){
17653 this.maskEl.hide();
17657 onBeforeLoad: function()
17659 this.clearEvents();
17661 this.maskEl.show();
17675 * @class Roo.bootstrap.Popover
17676 * @extends Roo.bootstrap.Component
17677 * Bootstrap Popover class
17678 * @cfg {String} html contents of the popover (or false to use children..)
17679 * @cfg {String} title of popover (or false to hide)
17680 * @cfg {String} placement how it is placed
17681 * @cfg {String} trigger click || hover (or false to trigger manually)
17682 * @cfg {String} over what (parent or false to trigger manually.)
17683 * @cfg {Number} delay - delay before showing
17686 * Create a new Popover
17687 * @param {Object} config The config object
17690 Roo.bootstrap.Popover = function(config){
17691 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17697 * After the popover show
17699 * @param {Roo.bootstrap.Popover} this
17704 * After the popover hide
17706 * @param {Roo.bootstrap.Popover} this
17712 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17714 title: 'Fill in a title',
17717 placement : 'right',
17718 trigger : 'hover', // hover
17724 can_build_overlaid : false,
17726 getChildContainer : function()
17728 return this.el.select('.popover-content',true).first();
17731 getAutoCreate : function(){
17734 cls : 'popover roo-dynamic',
17735 style: 'display:block',
17741 cls : 'popover-inner',
17745 cls: 'popover-title popover-header',
17749 cls : 'popover-content popover-body',
17760 setTitle: function(str)
17763 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17765 setContent: function(str)
17768 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17770 // as it get's added to the bottom of the page.
17771 onRender : function(ct, position)
17773 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17775 var cfg = Roo.apply({}, this.getAutoCreate());
17779 cfg.cls += ' ' + this.cls;
17782 cfg.style = this.style;
17784 //Roo.log("adding to ");
17785 this.el = Roo.get(document.body).createChild(cfg, position);
17786 // Roo.log(this.el);
17791 initEvents : function()
17793 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17794 this.el.enableDisplayMode('block');
17796 if (this.over === false) {
17799 if (this.triggers === false) {
17802 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17803 var triggers = this.trigger ? this.trigger.split(' ') : [];
17804 Roo.each(triggers, function(trigger) {
17806 if (trigger == 'click') {
17807 on_el.on('click', this.toggle, this);
17808 } else if (trigger != 'manual') {
17809 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17810 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17812 on_el.on(eventIn ,this.enter, this);
17813 on_el.on(eventOut, this.leave, this);
17824 toggle : function () {
17825 this.hoverState == 'in' ? this.leave() : this.enter();
17828 enter : function () {
17830 clearTimeout(this.timeout);
17832 this.hoverState = 'in';
17834 if (!this.delay || !this.delay.show) {
17839 this.timeout = setTimeout(function () {
17840 if (_t.hoverState == 'in') {
17843 }, this.delay.show)
17846 leave : function() {
17847 clearTimeout(this.timeout);
17849 this.hoverState = 'out';
17851 if (!this.delay || !this.delay.hide) {
17856 this.timeout = setTimeout(function () {
17857 if (_t.hoverState == 'out') {
17860 }, this.delay.hide)
17863 show : function (on_el)
17866 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17870 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17871 if (this.html !== false) {
17872 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17874 this.el.removeClass([
17875 'fade','top','bottom', 'left', 'right','in',
17876 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17878 if (!this.title.length) {
17879 this.el.select('.popover-title',true).hide();
17882 var placement = typeof this.placement == 'function' ?
17883 this.placement.call(this, this.el, on_el) :
17886 var autoToken = /\s?auto?\s?/i;
17887 var autoPlace = autoToken.test(placement);
17889 placement = placement.replace(autoToken, '') || 'top';
17893 //this.el.setXY([0,0]);
17895 this.el.dom.style.display='block';
17896 this.el.addClass(placement);
17898 //this.el.appendTo(on_el);
17900 var p = this.getPosition();
17901 var box = this.el.getBox();
17906 var align = Roo.bootstrap.Popover.alignment[placement];
17909 this.el.alignTo(on_el, align[0],align[1]);
17910 //var arrow = this.el.select('.arrow',true).first();
17911 //arrow.set(align[2],
17913 this.el.addClass('in');
17916 if (this.el.hasClass('fade')) {
17920 this.hoverState = 'in';
17922 this.fireEvent('show', this);
17927 this.el.setXY([0,0]);
17928 this.el.removeClass('in');
17930 this.hoverState = null;
17932 this.fireEvent('hide', this);
17937 Roo.bootstrap.Popover.alignment = {
17938 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17939 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17940 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17941 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17952 * @class Roo.bootstrap.Progress
17953 * @extends Roo.bootstrap.Component
17954 * Bootstrap Progress class
17955 * @cfg {Boolean} striped striped of the progress bar
17956 * @cfg {Boolean} active animated of the progress bar
17960 * Create a new Progress
17961 * @param {Object} config The config object
17964 Roo.bootstrap.Progress = function(config){
17965 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17968 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17973 getAutoCreate : function(){
17981 cfg.cls += ' progress-striped';
17985 cfg.cls += ' active';
18004 * @class Roo.bootstrap.ProgressBar
18005 * @extends Roo.bootstrap.Component
18006 * Bootstrap ProgressBar class
18007 * @cfg {Number} aria_valuenow aria-value now
18008 * @cfg {Number} aria_valuemin aria-value min
18009 * @cfg {Number} aria_valuemax aria-value max
18010 * @cfg {String} label label for the progress bar
18011 * @cfg {String} panel (success | info | warning | danger )
18012 * @cfg {String} role role of the progress bar
18013 * @cfg {String} sr_only text
18017 * Create a new ProgressBar
18018 * @param {Object} config The config object
18021 Roo.bootstrap.ProgressBar = function(config){
18022 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18025 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18029 aria_valuemax : 100,
18035 getAutoCreate : function()
18040 cls: 'progress-bar',
18041 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18053 cfg.role = this.role;
18056 if(this.aria_valuenow){
18057 cfg['aria-valuenow'] = this.aria_valuenow;
18060 if(this.aria_valuemin){
18061 cfg['aria-valuemin'] = this.aria_valuemin;
18064 if(this.aria_valuemax){
18065 cfg['aria-valuemax'] = this.aria_valuemax;
18068 if(this.label && !this.sr_only){
18069 cfg.html = this.label;
18073 cfg.cls += ' progress-bar-' + this.panel;
18079 update : function(aria_valuenow)
18081 this.aria_valuenow = aria_valuenow;
18083 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18098 * @class Roo.bootstrap.TabGroup
18099 * @extends Roo.bootstrap.Column
18100 * Bootstrap Column class
18101 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18102 * @cfg {Boolean} carousel true to make the group behave like a carousel
18103 * @cfg {Boolean} bullets show bullets for the panels
18104 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18105 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18106 * @cfg {Boolean} showarrow (true|false) show arrow default true
18109 * Create a new TabGroup
18110 * @param {Object} config The config object
18113 Roo.bootstrap.TabGroup = function(config){
18114 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18116 this.navId = Roo.id();
18119 Roo.bootstrap.TabGroup.register(this);
18123 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18126 transition : false,
18131 slideOnTouch : false,
18134 getAutoCreate : function()
18136 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18138 cfg.cls += ' tab-content';
18140 if (this.carousel) {
18141 cfg.cls += ' carousel slide';
18144 cls : 'carousel-inner',
18148 if(this.bullets && !Roo.isTouch){
18151 cls : 'carousel-bullets',
18155 if(this.bullets_cls){
18156 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18163 cfg.cn[0].cn.push(bullets);
18166 if(this.showarrow){
18167 cfg.cn[0].cn.push({
18169 class : 'carousel-arrow',
18173 class : 'carousel-prev',
18177 class : 'fa fa-chevron-left'
18183 class : 'carousel-next',
18187 class : 'fa fa-chevron-right'
18200 initEvents: function()
18202 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18203 // this.el.on("touchstart", this.onTouchStart, this);
18206 if(this.autoslide){
18209 this.slideFn = window.setInterval(function() {
18210 _this.showPanelNext();
18214 if(this.showarrow){
18215 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18216 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18222 // onTouchStart : function(e, el, o)
18224 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18228 // this.showPanelNext();
18232 getChildContainer : function()
18234 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18238 * register a Navigation item
18239 * @param {Roo.bootstrap.NavItem} the navitem to add
18241 register : function(item)
18243 this.tabs.push( item);
18244 item.navId = this.navId; // not really needed..
18249 getActivePanel : function()
18252 Roo.each(this.tabs, function(t) {
18262 getPanelByName : function(n)
18265 Roo.each(this.tabs, function(t) {
18266 if (t.tabId == n) {
18274 indexOfPanel : function(p)
18277 Roo.each(this.tabs, function(t,i) {
18278 if (t.tabId == p.tabId) {
18287 * show a specific panel
18288 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18289 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18291 showPanel : function (pan)
18293 if(this.transition || typeof(pan) == 'undefined'){
18294 Roo.log("waiting for the transitionend");
18298 if (typeof(pan) == 'number') {
18299 pan = this.tabs[pan];
18302 if (typeof(pan) == 'string') {
18303 pan = this.getPanelByName(pan);
18306 var cur = this.getActivePanel();
18309 Roo.log('pan or acitve pan is undefined');
18313 if (pan.tabId == this.getActivePanel().tabId) {
18317 if (false === cur.fireEvent('beforedeactivate')) {
18321 if(this.bullets > 0 && !Roo.isTouch){
18322 this.setActiveBullet(this.indexOfPanel(pan));
18325 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18327 this.transition = true;
18328 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18329 var lr = dir == 'next' ? 'left' : 'right';
18330 pan.el.addClass(dir); // or prev
18331 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18332 cur.el.addClass(lr); // or right
18333 pan.el.addClass(lr);
18336 cur.el.on('transitionend', function() {
18337 Roo.log("trans end?");
18339 pan.el.removeClass([lr,dir]);
18340 pan.setActive(true);
18342 cur.el.removeClass([lr]);
18343 cur.setActive(false);
18345 _this.transition = false;
18347 }, this, { single: true } );
18352 cur.setActive(false);
18353 pan.setActive(true);
18358 showPanelNext : function()
18360 var i = this.indexOfPanel(this.getActivePanel());
18362 if (i >= this.tabs.length - 1 && !this.autoslide) {
18366 if (i >= this.tabs.length - 1 && this.autoslide) {
18370 this.showPanel(this.tabs[i+1]);
18373 showPanelPrev : function()
18375 var i = this.indexOfPanel(this.getActivePanel());
18377 if (i < 1 && !this.autoslide) {
18381 if (i < 1 && this.autoslide) {
18382 i = this.tabs.length;
18385 this.showPanel(this.tabs[i-1]);
18389 addBullet: function()
18391 if(!this.bullets || Roo.isTouch){
18394 var ctr = this.el.select('.carousel-bullets',true).first();
18395 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18396 var bullet = ctr.createChild({
18397 cls : 'bullet bullet-' + i
18398 },ctr.dom.lastChild);
18403 bullet.on('click', (function(e, el, o, ii, t){
18405 e.preventDefault();
18407 this.showPanel(ii);
18409 if(this.autoslide && this.slideFn){
18410 clearInterval(this.slideFn);
18411 this.slideFn = window.setInterval(function() {
18412 _this.showPanelNext();
18416 }).createDelegate(this, [i, bullet], true));
18421 setActiveBullet : function(i)
18427 Roo.each(this.el.select('.bullet', true).elements, function(el){
18428 el.removeClass('selected');
18431 var bullet = this.el.select('.bullet-' + i, true).first();
18437 bullet.addClass('selected');
18448 Roo.apply(Roo.bootstrap.TabGroup, {
18452 * register a Navigation Group
18453 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18455 register : function(navgrp)
18457 this.groups[navgrp.navId] = navgrp;
18461 * fetch a Navigation Group based on the navigation ID
18462 * if one does not exist , it will get created.
18463 * @param {string} the navgroup to add
18464 * @returns {Roo.bootstrap.NavGroup} the navgroup
18466 get: function(navId) {
18467 if (typeof(this.groups[navId]) == 'undefined') {
18468 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18470 return this.groups[navId] ;
18485 * @class Roo.bootstrap.TabPanel
18486 * @extends Roo.bootstrap.Component
18487 * Bootstrap TabPanel class
18488 * @cfg {Boolean} active panel active
18489 * @cfg {String} html panel content
18490 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18491 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18492 * @cfg {String} href click to link..
18496 * Create a new TabPanel
18497 * @param {Object} config The config object
18500 Roo.bootstrap.TabPanel = function(config){
18501 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18505 * Fires when the active status changes
18506 * @param {Roo.bootstrap.TabPanel} this
18507 * @param {Boolean} state the new state
18512 * @event beforedeactivate
18513 * Fires before a tab is de-activated - can be used to do validation on a form.
18514 * @param {Roo.bootstrap.TabPanel} this
18515 * @return {Boolean} false if there is an error
18518 'beforedeactivate': true
18521 this.tabId = this.tabId || Roo.id();
18525 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18533 getAutoCreate : function(){
18536 // item is needed for carousel - not sure if it has any effect otherwise
18537 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18538 html: this.html || ''
18542 cfg.cls += ' active';
18546 cfg.tabId = this.tabId;
18553 initEvents: function()
18555 var p = this.parent();
18557 this.navId = this.navId || p.navId;
18559 if (typeof(this.navId) != 'undefined') {
18560 // not really needed.. but just in case.. parent should be a NavGroup.
18561 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18565 var i = tg.tabs.length - 1;
18567 if(this.active && tg.bullets > 0 && i < tg.bullets){
18568 tg.setActiveBullet(i);
18572 this.el.on('click', this.onClick, this);
18575 this.el.on("touchstart", this.onTouchStart, this);
18576 this.el.on("touchmove", this.onTouchMove, this);
18577 this.el.on("touchend", this.onTouchEnd, this);
18582 onRender : function(ct, position)
18584 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18587 setActive : function(state)
18589 Roo.log("panel - set active " + this.tabId + "=" + state);
18591 this.active = state;
18593 this.el.removeClass('active');
18595 } else if (!this.el.hasClass('active')) {
18596 this.el.addClass('active');
18599 this.fireEvent('changed', this, state);
18602 onClick : function(e)
18604 e.preventDefault();
18606 if(!this.href.length){
18610 window.location.href = this.href;
18619 onTouchStart : function(e)
18621 this.swiping = false;
18623 this.startX = e.browserEvent.touches[0].clientX;
18624 this.startY = e.browserEvent.touches[0].clientY;
18627 onTouchMove : function(e)
18629 this.swiping = true;
18631 this.endX = e.browserEvent.touches[0].clientX;
18632 this.endY = e.browserEvent.touches[0].clientY;
18635 onTouchEnd : function(e)
18642 var tabGroup = this.parent();
18644 if(this.endX > this.startX){ // swiping right
18645 tabGroup.showPanelPrev();
18649 if(this.startX > this.endX){ // swiping left
18650 tabGroup.showPanelNext();
18669 * @class Roo.bootstrap.DateField
18670 * @extends Roo.bootstrap.Input
18671 * Bootstrap DateField class
18672 * @cfg {Number} weekStart default 0
18673 * @cfg {String} viewMode default empty, (months|years)
18674 * @cfg {String} minViewMode default empty, (months|years)
18675 * @cfg {Number} startDate default -Infinity
18676 * @cfg {Number} endDate default Infinity
18677 * @cfg {Boolean} todayHighlight default false
18678 * @cfg {Boolean} todayBtn default false
18679 * @cfg {Boolean} calendarWeeks default false
18680 * @cfg {Object} daysOfWeekDisabled default empty
18681 * @cfg {Boolean} singleMode default false (true | false)
18683 * @cfg {Boolean} keyboardNavigation default true
18684 * @cfg {String} language default en
18687 * Create a new DateField
18688 * @param {Object} config The config object
18691 Roo.bootstrap.DateField = function(config){
18692 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18696 * Fires when this field show.
18697 * @param {Roo.bootstrap.DateField} this
18698 * @param {Mixed} date The date value
18703 * Fires when this field hide.
18704 * @param {Roo.bootstrap.DateField} this
18705 * @param {Mixed} date The date value
18710 * Fires when select a date.
18711 * @param {Roo.bootstrap.DateField} this
18712 * @param {Mixed} date The date value
18716 * @event beforeselect
18717 * Fires when before select a date.
18718 * @param {Roo.bootstrap.DateField} this
18719 * @param {Mixed} date The date value
18721 beforeselect : true
18725 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18728 * @cfg {String} format
18729 * The default date format string which can be overriden for localization support. The format must be
18730 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18734 * @cfg {String} altFormats
18735 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18736 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18738 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18746 todayHighlight : false,
18752 keyboardNavigation: true,
18754 calendarWeeks: false,
18756 startDate: -Infinity,
18760 daysOfWeekDisabled: [],
18764 singleMode : false,
18766 UTCDate: function()
18768 return new Date(Date.UTC.apply(Date, arguments));
18771 UTCToday: function()
18773 var today = new Date();
18774 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18777 getDate: function() {
18778 var d = this.getUTCDate();
18779 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18782 getUTCDate: function() {
18786 setDate: function(d) {
18787 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18790 setUTCDate: function(d) {
18792 this.setValue(this.formatDate(this.date));
18795 onRender: function(ct, position)
18798 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18800 this.language = this.language || 'en';
18801 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18802 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18804 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18805 this.format = this.format || 'm/d/y';
18806 this.isInline = false;
18807 this.isInput = true;
18808 this.component = this.el.select('.add-on', true).first() || false;
18809 this.component = (this.component && this.component.length === 0) ? false : this.component;
18810 this.hasInput = this.component && this.inputEl().length;
18812 if (typeof(this.minViewMode === 'string')) {
18813 switch (this.minViewMode) {
18815 this.minViewMode = 1;
18818 this.minViewMode = 2;
18821 this.minViewMode = 0;
18826 if (typeof(this.viewMode === 'string')) {
18827 switch (this.viewMode) {
18840 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18842 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18844 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18846 this.picker().on('mousedown', this.onMousedown, this);
18847 this.picker().on('click', this.onClick, this);
18849 this.picker().addClass('datepicker-dropdown');
18851 this.startViewMode = this.viewMode;
18853 if(this.singleMode){
18854 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18855 v.setVisibilityMode(Roo.Element.DISPLAY);
18859 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18860 v.setStyle('width', '189px');
18864 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18865 if(!this.calendarWeeks){
18870 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18871 v.attr('colspan', function(i, val){
18872 return parseInt(val) + 1;
18877 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18879 this.setStartDate(this.startDate);
18880 this.setEndDate(this.endDate);
18882 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18889 if(this.isInline) {
18894 picker : function()
18896 return this.pickerEl;
18897 // return this.el.select('.datepicker', true).first();
18900 fillDow: function()
18902 var dowCnt = this.weekStart;
18911 if(this.calendarWeeks){
18919 while (dowCnt < this.weekStart + 7) {
18923 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18927 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18930 fillMonths: function()
18933 var months = this.picker().select('>.datepicker-months td', true).first();
18935 months.dom.innerHTML = '';
18941 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18944 months.createChild(month);
18951 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;
18953 if (this.date < this.startDate) {
18954 this.viewDate = new Date(this.startDate);
18955 } else if (this.date > this.endDate) {
18956 this.viewDate = new Date(this.endDate);
18958 this.viewDate = new Date(this.date);
18966 var d = new Date(this.viewDate),
18967 year = d.getUTCFullYear(),
18968 month = d.getUTCMonth(),
18969 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18970 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18971 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18972 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18973 currentDate = this.date && this.date.valueOf(),
18974 today = this.UTCToday();
18976 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18978 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18980 // this.picker.select('>tfoot th.today').
18981 // .text(dates[this.language].today)
18982 // .toggle(this.todayBtn !== false);
18984 this.updateNavArrows();
18987 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18989 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18991 prevMonth.setUTCDate(day);
18993 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18995 var nextMonth = new Date(prevMonth);
18997 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18999 nextMonth = nextMonth.valueOf();
19001 var fillMonths = false;
19003 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19005 while(prevMonth.valueOf() <= nextMonth) {
19008 if (prevMonth.getUTCDay() === this.weekStart) {
19010 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19018 if(this.calendarWeeks){
19019 // ISO 8601: First week contains first thursday.
19020 // ISO also states week starts on Monday, but we can be more abstract here.
19022 // Start of current week: based on weekstart/current date
19023 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19024 // Thursday of this week
19025 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19026 // First Thursday of year, year from thursday
19027 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19028 // Calendar week: ms between thursdays, div ms per day, div 7 days
19029 calWeek = (th - yth) / 864e5 / 7 + 1;
19031 fillMonths.cn.push({
19039 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19041 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19044 if (this.todayHighlight &&
19045 prevMonth.getUTCFullYear() == today.getFullYear() &&
19046 prevMonth.getUTCMonth() == today.getMonth() &&
19047 prevMonth.getUTCDate() == today.getDate()) {
19048 clsName += ' today';
19051 if (currentDate && prevMonth.valueOf() === currentDate) {
19052 clsName += ' active';
19055 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19056 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19057 clsName += ' disabled';
19060 fillMonths.cn.push({
19062 cls: 'day ' + clsName,
19063 html: prevMonth.getDate()
19066 prevMonth.setDate(prevMonth.getDate()+1);
19069 var currentYear = this.date && this.date.getUTCFullYear();
19070 var currentMonth = this.date && this.date.getUTCMonth();
19072 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19074 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19075 v.removeClass('active');
19077 if(currentYear === year && k === currentMonth){
19078 v.addClass('active');
19081 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19082 v.addClass('disabled');
19088 year = parseInt(year/10, 10) * 10;
19090 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19092 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19095 for (var i = -1; i < 11; i++) {
19096 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19098 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19106 showMode: function(dir)
19109 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19112 Roo.each(this.picker().select('>div',true).elements, function(v){
19113 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19116 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19121 if(this.isInline) {
19125 this.picker().removeClass(['bottom', 'top']);
19127 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19129 * place to the top of element!
19133 this.picker().addClass('top');
19134 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19139 this.picker().addClass('bottom');
19141 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19144 parseDate : function(value)
19146 if(!value || value instanceof Date){
19149 var v = Date.parseDate(value, this.format);
19150 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19151 v = Date.parseDate(value, 'Y-m-d');
19153 if(!v && this.altFormats){
19154 if(!this.altFormatsArray){
19155 this.altFormatsArray = this.altFormats.split("|");
19157 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19158 v = Date.parseDate(value, this.altFormatsArray[i]);
19164 formatDate : function(date, fmt)
19166 return (!date || !(date instanceof Date)) ?
19167 date : date.dateFormat(fmt || this.format);
19170 onFocus : function()
19172 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19176 onBlur : function()
19178 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19180 var d = this.inputEl().getValue();
19187 showPopup : function()
19189 this.picker().show();
19193 this.fireEvent('showpopup', this, this.date);
19196 hidePopup : function()
19198 if(this.isInline) {
19201 this.picker().hide();
19202 this.viewMode = this.startViewMode;
19205 this.fireEvent('hidepopup', this, this.date);
19209 onMousedown: function(e)
19211 e.stopPropagation();
19212 e.preventDefault();
19217 Roo.bootstrap.DateField.superclass.keyup.call(this);
19221 setValue: function(v)
19223 if(this.fireEvent('beforeselect', this, v) !== false){
19224 var d = new Date(this.parseDate(v) ).clearTime();
19226 if(isNaN(d.getTime())){
19227 this.date = this.viewDate = '';
19228 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19232 v = this.formatDate(d);
19234 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19236 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19240 this.fireEvent('select', this, this.date);
19244 getValue: function()
19246 return this.formatDate(this.date);
19249 fireKey: function(e)
19251 if (!this.picker().isVisible()){
19252 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19258 var dateChanged = false,
19260 newDate, newViewDate;
19265 e.preventDefault();
19269 if (!this.keyboardNavigation) {
19272 dir = e.keyCode == 37 ? -1 : 1;
19275 newDate = this.moveYear(this.date, dir);
19276 newViewDate = this.moveYear(this.viewDate, dir);
19277 } else if (e.shiftKey){
19278 newDate = this.moveMonth(this.date, dir);
19279 newViewDate = this.moveMonth(this.viewDate, dir);
19281 newDate = new Date(this.date);
19282 newDate.setUTCDate(this.date.getUTCDate() + dir);
19283 newViewDate = new Date(this.viewDate);
19284 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19286 if (this.dateWithinRange(newDate)){
19287 this.date = newDate;
19288 this.viewDate = newViewDate;
19289 this.setValue(this.formatDate(this.date));
19291 e.preventDefault();
19292 dateChanged = true;
19297 if (!this.keyboardNavigation) {
19300 dir = e.keyCode == 38 ? -1 : 1;
19302 newDate = this.moveYear(this.date, dir);
19303 newViewDate = this.moveYear(this.viewDate, dir);
19304 } else if (e.shiftKey){
19305 newDate = this.moveMonth(this.date, dir);
19306 newViewDate = this.moveMonth(this.viewDate, dir);
19308 newDate = new Date(this.date);
19309 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19310 newViewDate = new Date(this.viewDate);
19311 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19313 if (this.dateWithinRange(newDate)){
19314 this.date = newDate;
19315 this.viewDate = newViewDate;
19316 this.setValue(this.formatDate(this.date));
19318 e.preventDefault();
19319 dateChanged = true;
19323 this.setValue(this.formatDate(this.date));
19325 e.preventDefault();
19328 this.setValue(this.formatDate(this.date));
19342 onClick: function(e)
19344 e.stopPropagation();
19345 e.preventDefault();
19347 var target = e.getTarget();
19349 if(target.nodeName.toLowerCase() === 'i'){
19350 target = Roo.get(target).dom.parentNode;
19353 var nodeName = target.nodeName;
19354 var className = target.className;
19355 var html = target.innerHTML;
19356 //Roo.log(nodeName);
19358 switch(nodeName.toLowerCase()) {
19360 switch(className) {
19366 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19367 switch(this.viewMode){
19369 this.viewDate = this.moveMonth(this.viewDate, dir);
19373 this.viewDate = this.moveYear(this.viewDate, dir);
19379 var date = new Date();
19380 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19382 this.setValue(this.formatDate(this.date));
19389 if (className.indexOf('disabled') < 0) {
19390 this.viewDate.setUTCDate(1);
19391 if (className.indexOf('month') > -1) {
19392 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19394 var year = parseInt(html, 10) || 0;
19395 this.viewDate.setUTCFullYear(year);
19399 if(this.singleMode){
19400 this.setValue(this.formatDate(this.viewDate));
19411 //Roo.log(className);
19412 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19413 var day = parseInt(html, 10) || 1;
19414 var year = this.viewDate.getUTCFullYear(),
19415 month = this.viewDate.getUTCMonth();
19417 if (className.indexOf('old') > -1) {
19424 } else if (className.indexOf('new') > -1) {
19432 //Roo.log([year,month,day]);
19433 this.date = this.UTCDate(year, month, day,0,0,0,0);
19434 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19436 //Roo.log(this.formatDate(this.date));
19437 this.setValue(this.formatDate(this.date));
19444 setStartDate: function(startDate)
19446 this.startDate = startDate || -Infinity;
19447 if (this.startDate !== -Infinity) {
19448 this.startDate = this.parseDate(this.startDate);
19451 this.updateNavArrows();
19454 setEndDate: function(endDate)
19456 this.endDate = endDate || Infinity;
19457 if (this.endDate !== Infinity) {
19458 this.endDate = this.parseDate(this.endDate);
19461 this.updateNavArrows();
19464 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19466 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19467 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19468 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19470 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19471 return parseInt(d, 10);
19474 this.updateNavArrows();
19477 updateNavArrows: function()
19479 if(this.singleMode){
19483 var d = new Date(this.viewDate),
19484 year = d.getUTCFullYear(),
19485 month = d.getUTCMonth();
19487 Roo.each(this.picker().select('.prev', true).elements, function(v){
19489 switch (this.viewMode) {
19492 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19498 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19505 Roo.each(this.picker().select('.next', true).elements, function(v){
19507 switch (this.viewMode) {
19510 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19516 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19524 moveMonth: function(date, dir)
19529 var new_date = new Date(date.valueOf()),
19530 day = new_date.getUTCDate(),
19531 month = new_date.getUTCMonth(),
19532 mag = Math.abs(dir),
19534 dir = dir > 0 ? 1 : -1;
19537 // If going back one month, make sure month is not current month
19538 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19540 return new_date.getUTCMonth() == month;
19542 // If going forward one month, make sure month is as expected
19543 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19545 return new_date.getUTCMonth() != new_month;
19547 new_month = month + dir;
19548 new_date.setUTCMonth(new_month);
19549 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19550 if (new_month < 0 || new_month > 11) {
19551 new_month = (new_month + 12) % 12;
19554 // For magnitudes >1, move one month at a time...
19555 for (var i=0; i<mag; i++) {
19556 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19557 new_date = this.moveMonth(new_date, dir);
19559 // ...then reset the day, keeping it in the new month
19560 new_month = new_date.getUTCMonth();
19561 new_date.setUTCDate(day);
19563 return new_month != new_date.getUTCMonth();
19566 // Common date-resetting loop -- if date is beyond end of month, make it
19569 new_date.setUTCDate(--day);
19570 new_date.setUTCMonth(new_month);
19575 moveYear: function(date, dir)
19577 return this.moveMonth(date, dir*12);
19580 dateWithinRange: function(date)
19582 return date >= this.startDate && date <= this.endDate;
19588 this.picker().remove();
19591 validateValue : function(value)
19593 if(this.getVisibilityEl().hasClass('hidden')){
19597 if(value.length < 1) {
19598 if(this.allowBlank){
19604 if(value.length < this.minLength){
19607 if(value.length > this.maxLength){
19611 var vt = Roo.form.VTypes;
19612 if(!vt[this.vtype](value, this)){
19616 if(typeof this.validator == "function"){
19617 var msg = this.validator(value);
19623 if(this.regex && !this.regex.test(value)){
19627 if(typeof(this.parseDate(value)) == 'undefined'){
19631 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19635 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19645 this.date = this.viewDate = '';
19647 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19652 Roo.apply(Roo.bootstrap.DateField, {
19663 html: '<i class="fa fa-arrow-left"/>'
19673 html: '<i class="fa fa-arrow-right"/>'
19715 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19716 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19717 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19718 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19719 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19732 navFnc: 'FullYear',
19737 navFnc: 'FullYear',
19742 Roo.apply(Roo.bootstrap.DateField, {
19746 cls: 'datepicker dropdown-menu roo-dynamic',
19750 cls: 'datepicker-days',
19754 cls: 'table-condensed',
19756 Roo.bootstrap.DateField.head,
19760 Roo.bootstrap.DateField.footer
19767 cls: 'datepicker-months',
19771 cls: 'table-condensed',
19773 Roo.bootstrap.DateField.head,
19774 Roo.bootstrap.DateField.content,
19775 Roo.bootstrap.DateField.footer
19782 cls: 'datepicker-years',
19786 cls: 'table-condensed',
19788 Roo.bootstrap.DateField.head,
19789 Roo.bootstrap.DateField.content,
19790 Roo.bootstrap.DateField.footer
19809 * @class Roo.bootstrap.TimeField
19810 * @extends Roo.bootstrap.Input
19811 * Bootstrap DateField class
19815 * Create a new TimeField
19816 * @param {Object} config The config object
19819 Roo.bootstrap.TimeField = function(config){
19820 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19824 * Fires when this field show.
19825 * @param {Roo.bootstrap.DateField} thisthis
19826 * @param {Mixed} date The date value
19831 * Fires when this field hide.
19832 * @param {Roo.bootstrap.DateField} this
19833 * @param {Mixed} date The date value
19838 * Fires when select a date.
19839 * @param {Roo.bootstrap.DateField} this
19840 * @param {Mixed} date The date value
19846 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19849 * @cfg {String} format
19850 * The default time format string which can be overriden for localization support. The format must be
19851 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19855 onRender: function(ct, position)
19858 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19860 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19862 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19864 this.pop = this.picker().select('>.datepicker-time',true).first();
19865 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19867 this.picker().on('mousedown', this.onMousedown, this);
19868 this.picker().on('click', this.onClick, this);
19870 this.picker().addClass('datepicker-dropdown');
19875 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19876 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19877 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19878 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19879 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19880 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19884 fireKey: function(e){
19885 if (!this.picker().isVisible()){
19886 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19892 e.preventDefault();
19900 this.onTogglePeriod();
19903 this.onIncrementMinutes();
19906 this.onDecrementMinutes();
19915 onClick: function(e) {
19916 e.stopPropagation();
19917 e.preventDefault();
19920 picker : function()
19922 return this.el.select('.datepicker', true).first();
19925 fillTime: function()
19927 var time = this.pop.select('tbody', true).first();
19929 time.dom.innerHTML = '';
19944 cls: 'hours-up glyphicon glyphicon-chevron-up'
19964 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19985 cls: 'timepicker-hour',
20000 cls: 'timepicker-minute',
20015 cls: 'btn btn-primary period',
20037 cls: 'hours-down glyphicon glyphicon-chevron-down'
20057 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20075 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20082 var hours = this.time.getHours();
20083 var minutes = this.time.getMinutes();
20096 hours = hours - 12;
20100 hours = '0' + hours;
20104 minutes = '0' + minutes;
20107 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20108 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20109 this.pop.select('button', true).first().dom.innerHTML = period;
20115 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20117 var cls = ['bottom'];
20119 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20126 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20131 this.picker().addClass(cls.join('-'));
20135 Roo.each(cls, function(c){
20137 _this.picker().setTop(_this.inputEl().getHeight());
20141 _this.picker().setTop(0 - _this.picker().getHeight());
20146 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20150 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20157 onFocus : function()
20159 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20163 onBlur : function()
20165 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20171 this.picker().show();
20176 this.fireEvent('show', this, this.date);
20181 this.picker().hide();
20184 this.fireEvent('hide', this, this.date);
20187 setTime : function()
20190 this.setValue(this.time.format(this.format));
20192 this.fireEvent('select', this, this.date);
20197 onMousedown: function(e){
20198 e.stopPropagation();
20199 e.preventDefault();
20202 onIncrementHours: function()
20204 Roo.log('onIncrementHours');
20205 this.time = this.time.add(Date.HOUR, 1);
20210 onDecrementHours: function()
20212 Roo.log('onDecrementHours');
20213 this.time = this.time.add(Date.HOUR, -1);
20217 onIncrementMinutes: function()
20219 Roo.log('onIncrementMinutes');
20220 this.time = this.time.add(Date.MINUTE, 1);
20224 onDecrementMinutes: function()
20226 Roo.log('onDecrementMinutes');
20227 this.time = this.time.add(Date.MINUTE, -1);
20231 onTogglePeriod: function()
20233 Roo.log('onTogglePeriod');
20234 this.time = this.time.add(Date.HOUR, 12);
20241 Roo.apply(Roo.bootstrap.TimeField, {
20271 cls: 'btn btn-info ok',
20283 Roo.apply(Roo.bootstrap.TimeField, {
20287 cls: 'datepicker dropdown-menu',
20291 cls: 'datepicker-time',
20295 cls: 'table-condensed',
20297 Roo.bootstrap.TimeField.content,
20298 Roo.bootstrap.TimeField.footer
20317 * @class Roo.bootstrap.MonthField
20318 * @extends Roo.bootstrap.Input
20319 * Bootstrap MonthField class
20321 * @cfg {String} language default en
20324 * Create a new MonthField
20325 * @param {Object} config The config object
20328 Roo.bootstrap.MonthField = function(config){
20329 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20334 * Fires when this field show.
20335 * @param {Roo.bootstrap.MonthField} this
20336 * @param {Mixed} date The date value
20341 * Fires when this field hide.
20342 * @param {Roo.bootstrap.MonthField} this
20343 * @param {Mixed} date The date value
20348 * Fires when select a date.
20349 * @param {Roo.bootstrap.MonthField} this
20350 * @param {String} oldvalue The old value
20351 * @param {String} newvalue The new value
20357 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20359 onRender: function(ct, position)
20362 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20364 this.language = this.language || 'en';
20365 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20366 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20368 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20369 this.isInline = false;
20370 this.isInput = true;
20371 this.component = this.el.select('.add-on', true).first() || false;
20372 this.component = (this.component && this.component.length === 0) ? false : this.component;
20373 this.hasInput = this.component && this.inputEL().length;
20375 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20377 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20379 this.picker().on('mousedown', this.onMousedown, this);
20380 this.picker().on('click', this.onClick, this);
20382 this.picker().addClass('datepicker-dropdown');
20384 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20385 v.setStyle('width', '189px');
20392 if(this.isInline) {
20398 setValue: function(v, suppressEvent)
20400 var o = this.getValue();
20402 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20406 if(suppressEvent !== true){
20407 this.fireEvent('select', this, o, v);
20412 getValue: function()
20417 onClick: function(e)
20419 e.stopPropagation();
20420 e.preventDefault();
20422 var target = e.getTarget();
20424 if(target.nodeName.toLowerCase() === 'i'){
20425 target = Roo.get(target).dom.parentNode;
20428 var nodeName = target.nodeName;
20429 var className = target.className;
20430 var html = target.innerHTML;
20432 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20436 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20438 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20444 picker : function()
20446 return this.pickerEl;
20449 fillMonths: function()
20452 var months = this.picker().select('>.datepicker-months td', true).first();
20454 months.dom.innerHTML = '';
20460 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20463 months.createChild(month);
20472 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20473 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20476 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20477 e.removeClass('active');
20479 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20480 e.addClass('active');
20487 if(this.isInline) {
20491 this.picker().removeClass(['bottom', 'top']);
20493 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20495 * place to the top of element!
20499 this.picker().addClass('top');
20500 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20505 this.picker().addClass('bottom');
20507 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20510 onFocus : function()
20512 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20516 onBlur : function()
20518 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20520 var d = this.inputEl().getValue();
20529 this.picker().show();
20530 this.picker().select('>.datepicker-months', true).first().show();
20534 this.fireEvent('show', this, this.date);
20539 if(this.isInline) {
20542 this.picker().hide();
20543 this.fireEvent('hide', this, this.date);
20547 onMousedown: function(e)
20549 e.stopPropagation();
20550 e.preventDefault();
20555 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20559 fireKey: function(e)
20561 if (!this.picker().isVisible()){
20562 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20573 e.preventDefault();
20577 dir = e.keyCode == 37 ? -1 : 1;
20579 this.vIndex = this.vIndex + dir;
20581 if(this.vIndex < 0){
20585 if(this.vIndex > 11){
20589 if(isNaN(this.vIndex)){
20593 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20599 dir = e.keyCode == 38 ? -1 : 1;
20601 this.vIndex = this.vIndex + dir * 4;
20603 if(this.vIndex < 0){
20607 if(this.vIndex > 11){
20611 if(isNaN(this.vIndex)){
20615 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20620 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20621 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20625 e.preventDefault();
20628 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20629 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20645 this.picker().remove();
20650 Roo.apply(Roo.bootstrap.MonthField, {
20669 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20670 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20675 Roo.apply(Roo.bootstrap.MonthField, {
20679 cls: 'datepicker dropdown-menu roo-dynamic',
20683 cls: 'datepicker-months',
20687 cls: 'table-condensed',
20689 Roo.bootstrap.DateField.content
20709 * @class Roo.bootstrap.CheckBox
20710 * @extends Roo.bootstrap.Input
20711 * Bootstrap CheckBox class
20713 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20714 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20715 * @cfg {String} boxLabel The text that appears beside the checkbox
20716 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20717 * @cfg {Boolean} checked initnal the element
20718 * @cfg {Boolean} inline inline the element (default false)
20719 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20720 * @cfg {String} tooltip label tooltip
20723 * Create a new CheckBox
20724 * @param {Object} config The config object
20727 Roo.bootstrap.CheckBox = function(config){
20728 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20733 * Fires when the element is checked or unchecked.
20734 * @param {Roo.bootstrap.CheckBox} this This input
20735 * @param {Boolean} checked The new checked value
20740 * Fires when the element is click.
20741 * @param {Roo.bootstrap.CheckBox} this This input
20748 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20750 inputType: 'checkbox',
20759 getAutoCreate : function()
20761 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20767 cfg.cls = 'form-group ' + this.inputType; //input-group
20770 cfg.cls += ' ' + this.inputType + '-inline';
20776 type : this.inputType,
20777 value : this.inputValue,
20778 cls : 'roo-' + this.inputType, //'form-box',
20779 placeholder : this.placeholder || ''
20783 if(this.inputType != 'radio'){
20787 cls : 'roo-hidden-value',
20788 value : this.checked ? this.inputValue : this.valueOff
20793 if (this.weight) { // Validity check?
20794 cfg.cls += " " + this.inputType + "-" + this.weight;
20797 if (this.disabled) {
20798 input.disabled=true;
20802 input.checked = this.checked;
20807 input.name = this.name;
20809 if(this.inputType != 'radio'){
20810 hidden.name = this.name;
20811 input.name = '_hidden_' + this.name;
20816 input.cls += ' input-' + this.size;
20821 ['xs','sm','md','lg'].map(function(size){
20822 if (settings[size]) {
20823 cfg.cls += ' col-' + size + '-' + settings[size];
20827 var inputblock = input;
20829 if (this.before || this.after) {
20832 cls : 'input-group',
20837 inputblock.cn.push({
20839 cls : 'input-group-addon',
20844 inputblock.cn.push(input);
20846 if(this.inputType != 'radio'){
20847 inputblock.cn.push(hidden);
20851 inputblock.cn.push({
20853 cls : 'input-group-addon',
20860 if (align ==='left' && this.fieldLabel.length) {
20861 // Roo.log("left and has label");
20866 cls : 'control-label',
20867 html : this.fieldLabel
20877 if(this.labelWidth > 12){
20878 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20881 if(this.labelWidth < 13 && this.labelmd == 0){
20882 this.labelmd = this.labelWidth;
20885 if(this.labellg > 0){
20886 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20887 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20890 if(this.labelmd > 0){
20891 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20892 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20895 if(this.labelsm > 0){
20896 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20897 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20900 if(this.labelxs > 0){
20901 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20902 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20905 } else if ( this.fieldLabel.length) {
20906 // Roo.log(" label");
20910 tag: this.boxLabel ? 'span' : 'label',
20912 cls: 'control-label box-input-label',
20913 //cls : 'input-group-addon',
20914 html : this.fieldLabel
20923 // Roo.log(" no label && no align");
20924 cfg.cn = [ inputblock ] ;
20930 var boxLabelCfg = {
20932 //'for': id, // box label is handled by onclick - so no for...
20934 html: this.boxLabel
20938 boxLabelCfg.tooltip = this.tooltip;
20941 cfg.cn.push(boxLabelCfg);
20944 if(this.inputType != 'radio'){
20945 cfg.cn.push(hidden);
20953 * return the real input element.
20955 inputEl: function ()
20957 return this.el.select('input.roo-' + this.inputType,true).first();
20959 hiddenEl: function ()
20961 return this.el.select('input.roo-hidden-value',true).first();
20964 labelEl: function()
20966 return this.el.select('label.control-label',true).first();
20968 /* depricated... */
20972 return this.labelEl();
20975 boxLabelEl: function()
20977 return this.el.select('label.box-label',true).first();
20980 initEvents : function()
20982 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20984 this.inputEl().on('click', this.onClick, this);
20986 if (this.boxLabel) {
20987 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20990 this.startValue = this.getValue();
20993 Roo.bootstrap.CheckBox.register(this);
20997 onClick : function(e)
20999 if(this.fireEvent('click', this, e) !== false){
21000 this.setChecked(!this.checked);
21005 setChecked : function(state,suppressEvent)
21007 this.startValue = this.getValue();
21009 if(this.inputType == 'radio'){
21011 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21012 e.dom.checked = false;
21015 this.inputEl().dom.checked = true;
21017 this.inputEl().dom.value = this.inputValue;
21019 if(suppressEvent !== true){
21020 this.fireEvent('check', this, true);
21028 this.checked = state;
21030 this.inputEl().dom.checked = state;
21033 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21035 if(suppressEvent !== true){
21036 this.fireEvent('check', this, state);
21042 getValue : function()
21044 if(this.inputType == 'radio'){
21045 return this.getGroupValue();
21048 return this.hiddenEl().dom.value;
21052 getGroupValue : function()
21054 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21058 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21061 setValue : function(v,suppressEvent)
21063 if(this.inputType == 'radio'){
21064 this.setGroupValue(v, suppressEvent);
21068 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21073 setGroupValue : function(v, suppressEvent)
21075 this.startValue = this.getValue();
21077 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21078 e.dom.checked = false;
21080 if(e.dom.value == v){
21081 e.dom.checked = true;
21085 if(suppressEvent !== true){
21086 this.fireEvent('check', this, true);
21094 validate : function()
21096 if(this.getVisibilityEl().hasClass('hidden')){
21102 (this.inputType == 'radio' && this.validateRadio()) ||
21103 (this.inputType == 'checkbox' && this.validateCheckbox())
21109 this.markInvalid();
21113 validateRadio : function()
21115 if(this.getVisibilityEl().hasClass('hidden')){
21119 if(this.allowBlank){
21125 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21126 if(!e.dom.checked){
21138 validateCheckbox : function()
21141 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21142 //return (this.getValue() == this.inputValue) ? true : false;
21145 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21153 for(var i in group){
21154 if(group[i].el.isVisible(true)){
21162 for(var i in group){
21167 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21174 * Mark this field as valid
21176 markValid : function()
21180 this.fireEvent('valid', this);
21182 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21185 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21192 if(this.inputType == 'radio'){
21193 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21194 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21195 e.findParent('.form-group', false, true).addClass(_this.validClass);
21202 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21203 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21207 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21213 for(var i in group){
21214 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21215 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21220 * Mark this field as invalid
21221 * @param {String} msg The validation message
21223 markInvalid : function(msg)
21225 if(this.allowBlank){
21231 this.fireEvent('invalid', this, msg);
21233 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21236 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21240 label.markInvalid();
21243 if(this.inputType == 'radio'){
21244 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21245 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21246 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21253 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21254 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21258 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21264 for(var i in group){
21265 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21266 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21271 clearInvalid : function()
21273 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21275 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21277 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21279 if (label && label.iconEl) {
21280 label.iconEl.removeClass(label.validClass);
21281 label.iconEl.removeClass(label.invalidClass);
21285 disable : function()
21287 if(this.inputType != 'radio'){
21288 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21295 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21296 _this.getActionEl().addClass(this.disabledClass);
21297 e.dom.disabled = true;
21301 this.disabled = true;
21302 this.fireEvent("disable", this);
21306 enable : function()
21308 if(this.inputType != 'radio'){
21309 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21316 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21317 _this.getActionEl().removeClass(this.disabledClass);
21318 e.dom.disabled = false;
21322 this.disabled = false;
21323 this.fireEvent("enable", this);
21327 setBoxLabel : function(v)
21332 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21338 Roo.apply(Roo.bootstrap.CheckBox, {
21343 * register a CheckBox Group
21344 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21346 register : function(checkbox)
21348 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21349 this.groups[checkbox.groupId] = {};
21352 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21356 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21360 * fetch a CheckBox Group based on the group ID
21361 * @param {string} the group ID
21362 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21364 get: function(groupId) {
21365 if (typeof(this.groups[groupId]) == 'undefined') {
21369 return this.groups[groupId] ;
21382 * @class Roo.bootstrap.Radio
21383 * @extends Roo.bootstrap.Component
21384 * Bootstrap Radio class
21385 * @cfg {String} boxLabel - the label associated
21386 * @cfg {String} value - the value of radio
21389 * Create a new Radio
21390 * @param {Object} config The config object
21392 Roo.bootstrap.Radio = function(config){
21393 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21397 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21403 getAutoCreate : function()
21407 cls : 'form-group radio',
21412 html : this.boxLabel
21420 initEvents : function()
21422 this.parent().register(this);
21424 this.el.on('click', this.onClick, this);
21428 onClick : function(e)
21430 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21431 this.setChecked(true);
21435 setChecked : function(state, suppressEvent)
21437 this.parent().setValue(this.value, suppressEvent);
21441 setBoxLabel : function(v)
21446 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21461 * @class Roo.bootstrap.SecurePass
21462 * @extends Roo.bootstrap.Input
21463 * Bootstrap SecurePass class
21467 * Create a new SecurePass
21468 * @param {Object} config The config object
21471 Roo.bootstrap.SecurePass = function (config) {
21472 // these go here, so the translation tool can replace them..
21474 PwdEmpty: "Please type a password, and then retype it to confirm.",
21475 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21476 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21477 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21478 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21479 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21480 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21481 TooWeak: "Your password is Too Weak."
21483 this.meterLabel = "Password strength:";
21484 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21485 this.meterClass = [
21486 "roo-password-meter-tooweak",
21487 "roo-password-meter-weak",
21488 "roo-password-meter-medium",
21489 "roo-password-meter-strong",
21490 "roo-password-meter-grey"
21495 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21498 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21500 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21502 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21503 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21504 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21505 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21506 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21507 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21508 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21518 * @cfg {String/Object} Label for the strength meter (defaults to
21519 * 'Password strength:')
21524 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21525 * ['Weak', 'Medium', 'Strong'])
21528 pwdStrengths: false,
21541 initEvents: function ()
21543 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21545 if (this.el.is('input[type=password]') && Roo.isSafari) {
21546 this.el.on('keydown', this.SafariOnKeyDown, this);
21549 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21552 onRender: function (ct, position)
21554 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21555 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21556 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21558 this.trigger.createChild({
21563 cls: 'roo-password-meter-grey col-xs-12',
21566 //width: this.meterWidth + 'px'
21570 cls: 'roo-password-meter-text'
21576 if (this.hideTrigger) {
21577 this.trigger.setDisplayed(false);
21579 this.setSize(this.width || '', this.height || '');
21582 onDestroy: function ()
21584 if (this.trigger) {
21585 this.trigger.removeAllListeners();
21586 this.trigger.remove();
21589 this.wrap.remove();
21591 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21594 checkStrength: function ()
21596 var pwd = this.inputEl().getValue();
21597 if (pwd == this._lastPwd) {
21602 if (this.ClientSideStrongPassword(pwd)) {
21604 } else if (this.ClientSideMediumPassword(pwd)) {
21606 } else if (this.ClientSideWeakPassword(pwd)) {
21612 Roo.log('strength1: ' + strength);
21614 //var pm = this.trigger.child('div/div/div').dom;
21615 var pm = this.trigger.child('div/div');
21616 pm.removeClass(this.meterClass);
21617 pm.addClass(this.meterClass[strength]);
21620 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21622 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21624 this._lastPwd = pwd;
21628 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21630 this._lastPwd = '';
21632 var pm = this.trigger.child('div/div');
21633 pm.removeClass(this.meterClass);
21634 pm.addClass('roo-password-meter-grey');
21637 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21640 this.inputEl().dom.type='password';
21643 validateValue: function (value)
21646 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21649 if (value.length == 0) {
21650 if (this.allowBlank) {
21651 this.clearInvalid();
21655 this.markInvalid(this.errors.PwdEmpty);
21656 this.errorMsg = this.errors.PwdEmpty;
21664 if ('[\x21-\x7e]*'.match(value)) {
21665 this.markInvalid(this.errors.PwdBadChar);
21666 this.errorMsg = this.errors.PwdBadChar;
21669 if (value.length < 6) {
21670 this.markInvalid(this.errors.PwdShort);
21671 this.errorMsg = this.errors.PwdShort;
21674 if (value.length > 16) {
21675 this.markInvalid(this.errors.PwdLong);
21676 this.errorMsg = this.errors.PwdLong;
21680 if (this.ClientSideStrongPassword(value)) {
21682 } else if (this.ClientSideMediumPassword(value)) {
21684 } else if (this.ClientSideWeakPassword(value)) {
21691 if (strength < 2) {
21692 //this.markInvalid(this.errors.TooWeak);
21693 this.errorMsg = this.errors.TooWeak;
21698 console.log('strength2: ' + strength);
21700 //var pm = this.trigger.child('div/div/div').dom;
21702 var pm = this.trigger.child('div/div');
21703 pm.removeClass(this.meterClass);
21704 pm.addClass(this.meterClass[strength]);
21706 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21708 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21710 this.errorMsg = '';
21714 CharacterSetChecks: function (type)
21717 this.fResult = false;
21720 isctype: function (character, type)
21723 case this.kCapitalLetter:
21724 if (character >= 'A' && character <= 'Z') {
21729 case this.kSmallLetter:
21730 if (character >= 'a' && character <= 'z') {
21736 if (character >= '0' && character <= '9') {
21741 case this.kPunctuation:
21742 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21753 IsLongEnough: function (pwd, size)
21755 return !(pwd == null || isNaN(size) || pwd.length < size);
21758 SpansEnoughCharacterSets: function (word, nb)
21760 if (!this.IsLongEnough(word, nb))
21765 var characterSetChecks = new Array(
21766 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21767 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21770 for (var index = 0; index < word.length; ++index) {
21771 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21772 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21773 characterSetChecks[nCharSet].fResult = true;
21780 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21781 if (characterSetChecks[nCharSet].fResult) {
21786 if (nCharSets < nb) {
21792 ClientSideStrongPassword: function (pwd)
21794 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21797 ClientSideMediumPassword: function (pwd)
21799 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21802 ClientSideWeakPassword: function (pwd)
21804 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21807 })//<script type="text/javascript">
21810 * Based Ext JS Library 1.1.1
21811 * Copyright(c) 2006-2007, Ext JS, LLC.
21817 * @class Roo.HtmlEditorCore
21818 * @extends Roo.Component
21819 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21821 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21824 Roo.HtmlEditorCore = function(config){
21827 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21832 * @event initialize
21833 * Fires when the editor is fully initialized (including the iframe)
21834 * @param {Roo.HtmlEditorCore} this
21839 * Fires when the editor is first receives the focus. Any insertion must wait
21840 * until after this event.
21841 * @param {Roo.HtmlEditorCore} this
21845 * @event beforesync
21846 * Fires before the textarea is updated with content from the editor iframe. Return false
21847 * to cancel the sync.
21848 * @param {Roo.HtmlEditorCore} this
21849 * @param {String} html
21853 * @event beforepush
21854 * Fires before the iframe editor is updated with content from the textarea. Return false
21855 * to cancel the push.
21856 * @param {Roo.HtmlEditorCore} this
21857 * @param {String} html
21862 * Fires when the textarea is updated with content from the editor iframe.
21863 * @param {Roo.HtmlEditorCore} this
21864 * @param {String} html
21869 * Fires when the iframe editor is updated with content from the textarea.
21870 * @param {Roo.HtmlEditorCore} this
21871 * @param {String} html
21876 * @event editorevent
21877 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21878 * @param {Roo.HtmlEditorCore} this
21884 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21886 // defaults : white / black...
21887 this.applyBlacklists();
21894 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21898 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21904 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21909 * @cfg {Number} height (in pixels)
21913 * @cfg {Number} width (in pixels)
21918 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21921 stylesheets: false,
21926 // private properties
21927 validationEvent : false,
21929 initialized : false,
21931 sourceEditMode : false,
21932 onFocus : Roo.emptyFn,
21934 hideMode:'offsets',
21938 // blacklist + whitelisted elements..
21945 * Protected method that will not generally be called directly. It
21946 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21947 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21949 getDocMarkup : function(){
21953 // inherit styels from page...??
21954 if (this.stylesheets === false) {
21956 Roo.get(document.head).select('style').each(function(node) {
21957 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21960 Roo.get(document.head).select('link').each(function(node) {
21961 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21964 } else if (!this.stylesheets.length) {
21966 st = '<style type="text/css">' +
21967 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21970 st = '<style type="text/css">' +
21975 st += '<style type="text/css">' +
21976 'IMG { cursor: pointer } ' +
21979 var cls = 'roo-htmleditor-body';
21981 if(this.bodyCls.length){
21982 cls += ' ' + this.bodyCls;
21985 return '<html><head>' + st +
21986 //<style type="text/css">' +
21987 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21989 ' </head><body class="' + cls + '"></body></html>';
21993 onRender : function(ct, position)
21996 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21997 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22000 this.el.dom.style.border = '0 none';
22001 this.el.dom.setAttribute('tabIndex', -1);
22002 this.el.addClass('x-hidden hide');
22006 if(Roo.isIE){ // fix IE 1px bogus margin
22007 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22011 this.frameId = Roo.id();
22015 var iframe = this.owner.wrap.createChild({
22017 cls: 'form-control', // bootstrap..
22019 name: this.frameId,
22020 frameBorder : 'no',
22021 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22026 this.iframe = iframe.dom;
22028 this.assignDocWin();
22030 this.doc.designMode = 'on';
22033 this.doc.write(this.getDocMarkup());
22037 var task = { // must defer to wait for browser to be ready
22039 //console.log("run task?" + this.doc.readyState);
22040 this.assignDocWin();
22041 if(this.doc.body || this.doc.readyState == 'complete'){
22043 this.doc.designMode="on";
22047 Roo.TaskMgr.stop(task);
22048 this.initEditor.defer(10, this);
22055 Roo.TaskMgr.start(task);
22060 onResize : function(w, h)
22062 Roo.log('resize: ' +w + ',' + h );
22063 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22067 if(typeof w == 'number'){
22069 this.iframe.style.width = w + 'px';
22071 if(typeof h == 'number'){
22073 this.iframe.style.height = h + 'px';
22075 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22082 * Toggles the editor between standard and source edit mode.
22083 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22085 toggleSourceEdit : function(sourceEditMode){
22087 this.sourceEditMode = sourceEditMode === true;
22089 if(this.sourceEditMode){
22091 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22094 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22095 //this.iframe.className = '';
22098 //this.setSize(this.owner.wrap.getSize());
22099 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22106 * Protected method that will not generally be called directly. If you need/want
22107 * custom HTML cleanup, this is the method you should override.
22108 * @param {String} html The HTML to be cleaned
22109 * return {String} The cleaned HTML
22111 cleanHtml : function(html){
22112 html = String(html);
22113 if(html.length > 5){
22114 if(Roo.isSafari){ // strip safari nonsense
22115 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22118 if(html == ' '){
22125 * HTML Editor -> Textarea
22126 * Protected method that will not generally be called directly. Syncs the contents
22127 * of the editor iframe with the textarea.
22129 syncValue : function(){
22130 if(this.initialized){
22131 var bd = (this.doc.body || this.doc.documentElement);
22132 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22133 var html = bd.innerHTML;
22135 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22136 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22138 html = '<div style="'+m[0]+'">' + html + '</div>';
22141 html = this.cleanHtml(html);
22142 // fix up the special chars.. normaly like back quotes in word...
22143 // however we do not want to do this with chinese..
22144 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22145 var cc = b.charCodeAt();
22147 (cc >= 0x4E00 && cc < 0xA000 ) ||
22148 (cc >= 0x3400 && cc < 0x4E00 ) ||
22149 (cc >= 0xf900 && cc < 0xfb00 )
22155 if(this.owner.fireEvent('beforesync', this, html) !== false){
22156 this.el.dom.value = html;
22157 this.owner.fireEvent('sync', this, html);
22163 * Protected method that will not generally be called directly. Pushes the value of the textarea
22164 * into the iframe editor.
22166 pushValue : function(){
22167 if(this.initialized){
22168 var v = this.el.dom.value.trim();
22170 // if(v.length < 1){
22174 if(this.owner.fireEvent('beforepush', this, v) !== false){
22175 var d = (this.doc.body || this.doc.documentElement);
22177 this.cleanUpPaste();
22178 this.el.dom.value = d.innerHTML;
22179 this.owner.fireEvent('push', this, v);
22185 deferFocus : function(){
22186 this.focus.defer(10, this);
22190 focus : function(){
22191 if(this.win && !this.sourceEditMode){
22198 assignDocWin: function()
22200 var iframe = this.iframe;
22203 this.doc = iframe.contentWindow.document;
22204 this.win = iframe.contentWindow;
22206 // if (!Roo.get(this.frameId)) {
22209 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22210 // this.win = Roo.get(this.frameId).dom.contentWindow;
22212 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22216 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22217 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22222 initEditor : function(){
22223 //console.log("INIT EDITOR");
22224 this.assignDocWin();
22228 this.doc.designMode="on";
22230 this.doc.write(this.getDocMarkup());
22233 var dbody = (this.doc.body || this.doc.documentElement);
22234 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22235 // this copies styles from the containing element into thsi one..
22236 // not sure why we need all of this..
22237 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22239 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22240 //ss['background-attachment'] = 'fixed'; // w3c
22241 dbody.bgProperties = 'fixed'; // ie
22242 //Roo.DomHelper.applyStyles(dbody, ss);
22243 Roo.EventManager.on(this.doc, {
22244 //'mousedown': this.onEditorEvent,
22245 'mouseup': this.onEditorEvent,
22246 'dblclick': this.onEditorEvent,
22247 'click': this.onEditorEvent,
22248 'keyup': this.onEditorEvent,
22253 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22255 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22256 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22258 this.initialized = true;
22260 this.owner.fireEvent('initialize', this);
22265 onDestroy : function(){
22271 //for (var i =0; i < this.toolbars.length;i++) {
22272 // // fixme - ask toolbars for heights?
22273 // this.toolbars[i].onDestroy();
22276 //this.wrap.dom.innerHTML = '';
22277 //this.wrap.remove();
22282 onFirstFocus : function(){
22284 this.assignDocWin();
22287 this.activated = true;
22290 if(Roo.isGecko){ // prevent silly gecko errors
22292 var s = this.win.getSelection();
22293 if(!s.focusNode || s.focusNode.nodeType != 3){
22294 var r = s.getRangeAt(0);
22295 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22300 this.execCmd('useCSS', true);
22301 this.execCmd('styleWithCSS', false);
22304 this.owner.fireEvent('activate', this);
22308 adjustFont: function(btn){
22309 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22310 //if(Roo.isSafari){ // safari
22313 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22314 if(Roo.isSafari){ // safari
22315 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22316 v = (v < 10) ? 10 : v;
22317 v = (v > 48) ? 48 : v;
22318 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22323 v = Math.max(1, v+adjust);
22325 this.execCmd('FontSize', v );
22328 onEditorEvent : function(e)
22330 this.owner.fireEvent('editorevent', this, e);
22331 // this.updateToolbar();
22332 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22335 insertTag : function(tg)
22337 // could be a bit smarter... -> wrap the current selected tRoo..
22338 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22340 range = this.createRange(this.getSelection());
22341 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22342 wrappingNode.appendChild(range.extractContents());
22343 range.insertNode(wrappingNode);
22350 this.execCmd("formatblock", tg);
22354 insertText : function(txt)
22358 var range = this.createRange();
22359 range.deleteContents();
22360 //alert(Sender.getAttribute('label'));
22362 range.insertNode(this.doc.createTextNode(txt));
22368 * Executes a Midas editor command on the editor document and performs necessary focus and
22369 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22370 * @param {String} cmd The Midas command
22371 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22373 relayCmd : function(cmd, value){
22375 this.execCmd(cmd, value);
22376 this.owner.fireEvent('editorevent', this);
22377 //this.updateToolbar();
22378 this.owner.deferFocus();
22382 * Executes a Midas editor command directly on the editor document.
22383 * For visual commands, you should use {@link #relayCmd} instead.
22384 * <b>This should only be called after the editor is initialized.</b>
22385 * @param {String} cmd The Midas command
22386 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22388 execCmd : function(cmd, value){
22389 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22396 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22398 * @param {String} text | dom node..
22400 insertAtCursor : function(text)
22403 if(!this.activated){
22409 var r = this.doc.selection.createRange();
22420 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22424 // from jquery ui (MIT licenced)
22426 var win = this.win;
22428 if (win.getSelection && win.getSelection().getRangeAt) {
22429 range = win.getSelection().getRangeAt(0);
22430 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22431 range.insertNode(node);
22432 } else if (win.document.selection && win.document.selection.createRange) {
22433 // no firefox support
22434 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22435 win.document.selection.createRange().pasteHTML(txt);
22437 // no firefox support
22438 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22439 this.execCmd('InsertHTML', txt);
22448 mozKeyPress : function(e){
22450 var c = e.getCharCode(), cmd;
22453 c = String.fromCharCode(c).toLowerCase();
22467 this.cleanUpPaste.defer(100, this);
22475 e.preventDefault();
22483 fixKeys : function(){ // load time branching for fastest keydown performance
22485 return function(e){
22486 var k = e.getKey(), r;
22489 r = this.doc.selection.createRange();
22492 r.pasteHTML('    ');
22499 r = this.doc.selection.createRange();
22501 var target = r.parentElement();
22502 if(!target || target.tagName.toLowerCase() != 'li'){
22504 r.pasteHTML('<br />');
22510 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22511 this.cleanUpPaste.defer(100, this);
22517 }else if(Roo.isOpera){
22518 return function(e){
22519 var k = e.getKey();
22523 this.execCmd('InsertHTML','    ');
22526 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22527 this.cleanUpPaste.defer(100, this);
22532 }else if(Roo.isSafari){
22533 return function(e){
22534 var k = e.getKey();
22538 this.execCmd('InsertText','\t');
22542 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22543 this.cleanUpPaste.defer(100, this);
22551 getAllAncestors: function()
22553 var p = this.getSelectedNode();
22556 a.push(p); // push blank onto stack..
22557 p = this.getParentElement();
22561 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22565 a.push(this.doc.body);
22569 lastSelNode : false,
22572 getSelection : function()
22574 this.assignDocWin();
22575 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22578 getSelectedNode: function()
22580 // this may only work on Gecko!!!
22582 // should we cache this!!!!
22587 var range = this.createRange(this.getSelection()).cloneRange();
22590 var parent = range.parentElement();
22592 var testRange = range.duplicate();
22593 testRange.moveToElementText(parent);
22594 if (testRange.inRange(range)) {
22597 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22600 parent = parent.parentElement;
22605 // is ancestor a text element.
22606 var ac = range.commonAncestorContainer;
22607 if (ac.nodeType == 3) {
22608 ac = ac.parentNode;
22611 var ar = ac.childNodes;
22614 var other_nodes = [];
22615 var has_other_nodes = false;
22616 for (var i=0;i<ar.length;i++) {
22617 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22620 // fullly contained node.
22622 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22627 // probably selected..
22628 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22629 other_nodes.push(ar[i]);
22633 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22638 has_other_nodes = true;
22640 if (!nodes.length && other_nodes.length) {
22641 nodes= other_nodes;
22643 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22649 createRange: function(sel)
22651 // this has strange effects when using with
22652 // top toolbar - not sure if it's a great idea.
22653 //this.editor.contentWindow.focus();
22654 if (typeof sel != "undefined") {
22656 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22658 return this.doc.createRange();
22661 return this.doc.createRange();
22664 getParentElement: function()
22667 this.assignDocWin();
22668 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22670 var range = this.createRange(sel);
22673 var p = range.commonAncestorContainer;
22674 while (p.nodeType == 3) { // text node
22685 * Range intersection.. the hard stuff...
22689 * [ -- selected range --- ]
22693 * if end is before start or hits it. fail.
22694 * if start is after end or hits it fail.
22696 * if either hits (but other is outside. - then it's not
22702 // @see http://www.thismuchiknow.co.uk/?p=64.
22703 rangeIntersectsNode : function(range, node)
22705 var nodeRange = node.ownerDocument.createRange();
22707 nodeRange.selectNode(node);
22709 nodeRange.selectNodeContents(node);
22712 var rangeStartRange = range.cloneRange();
22713 rangeStartRange.collapse(true);
22715 var rangeEndRange = range.cloneRange();
22716 rangeEndRange.collapse(false);
22718 var nodeStartRange = nodeRange.cloneRange();
22719 nodeStartRange.collapse(true);
22721 var nodeEndRange = nodeRange.cloneRange();
22722 nodeEndRange.collapse(false);
22724 return rangeStartRange.compareBoundaryPoints(
22725 Range.START_TO_START, nodeEndRange) == -1 &&
22726 rangeEndRange.compareBoundaryPoints(
22727 Range.START_TO_START, nodeStartRange) == 1;
22731 rangeCompareNode : function(range, node)
22733 var nodeRange = node.ownerDocument.createRange();
22735 nodeRange.selectNode(node);
22737 nodeRange.selectNodeContents(node);
22741 range.collapse(true);
22743 nodeRange.collapse(true);
22745 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22746 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22748 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22750 var nodeIsBefore = ss == 1;
22751 var nodeIsAfter = ee == -1;
22753 if (nodeIsBefore && nodeIsAfter) {
22756 if (!nodeIsBefore && nodeIsAfter) {
22757 return 1; //right trailed.
22760 if (nodeIsBefore && !nodeIsAfter) {
22761 return 2; // left trailed.
22767 // private? - in a new class?
22768 cleanUpPaste : function()
22770 // cleans up the whole document..
22771 Roo.log('cleanuppaste');
22773 this.cleanUpChildren(this.doc.body);
22774 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22775 if (clean != this.doc.body.innerHTML) {
22776 this.doc.body.innerHTML = clean;
22781 cleanWordChars : function(input) {// change the chars to hex code
22782 var he = Roo.HtmlEditorCore;
22784 var output = input;
22785 Roo.each(he.swapCodes, function(sw) {
22786 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22788 output = output.replace(swapper, sw[1]);
22795 cleanUpChildren : function (n)
22797 if (!n.childNodes.length) {
22800 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22801 this.cleanUpChild(n.childNodes[i]);
22808 cleanUpChild : function (node)
22811 //console.log(node);
22812 if (node.nodeName == "#text") {
22813 // clean up silly Windows -- stuff?
22816 if (node.nodeName == "#comment") {
22817 node.parentNode.removeChild(node);
22818 // clean up silly Windows -- stuff?
22821 var lcname = node.tagName.toLowerCase();
22822 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22823 // whitelist of tags..
22825 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22827 node.parentNode.removeChild(node);
22832 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22834 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22835 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22837 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22838 // remove_keep_children = true;
22841 if (remove_keep_children) {
22842 this.cleanUpChildren(node);
22843 // inserts everything just before this node...
22844 while (node.childNodes.length) {
22845 var cn = node.childNodes[0];
22846 node.removeChild(cn);
22847 node.parentNode.insertBefore(cn, node);
22849 node.parentNode.removeChild(node);
22853 if (!node.attributes || !node.attributes.length) {
22854 this.cleanUpChildren(node);
22858 function cleanAttr(n,v)
22861 if (v.match(/^\./) || v.match(/^\//)) {
22864 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22867 if (v.match(/^#/)) {
22870 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22871 node.removeAttribute(n);
22875 var cwhite = this.cwhite;
22876 var cblack = this.cblack;
22878 function cleanStyle(n,v)
22880 if (v.match(/expression/)) { //XSS?? should we even bother..
22881 node.removeAttribute(n);
22885 var parts = v.split(/;/);
22888 Roo.each(parts, function(p) {
22889 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22893 var l = p.split(':').shift().replace(/\s+/g,'');
22894 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22896 if ( cwhite.length && cblack.indexOf(l) > -1) {
22897 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22898 //node.removeAttribute(n);
22902 // only allow 'c whitelisted system attributes'
22903 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22904 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22905 //node.removeAttribute(n);
22915 if (clean.length) {
22916 node.setAttribute(n, clean.join(';'));
22918 node.removeAttribute(n);
22924 for (var i = node.attributes.length-1; i > -1 ; i--) {
22925 var a = node.attributes[i];
22928 if (a.name.toLowerCase().substr(0,2)=='on') {
22929 node.removeAttribute(a.name);
22932 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22933 node.removeAttribute(a.name);
22936 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22937 cleanAttr(a.name,a.value); // fixme..
22940 if (a.name == 'style') {
22941 cleanStyle(a.name,a.value);
22944 /// clean up MS crap..
22945 // tecnically this should be a list of valid class'es..
22948 if (a.name == 'class') {
22949 if (a.value.match(/^Mso/)) {
22950 node.className = '';
22953 if (a.value.match(/^body$/)) {
22954 node.className = '';
22965 this.cleanUpChildren(node);
22971 * Clean up MS wordisms...
22973 cleanWord : function(node)
22978 this.cleanWord(this.doc.body);
22981 if (node.nodeName == "#text") {
22982 // clean up silly Windows -- stuff?
22985 if (node.nodeName == "#comment") {
22986 node.parentNode.removeChild(node);
22987 // clean up silly Windows -- stuff?
22991 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22992 node.parentNode.removeChild(node);
22996 // remove - but keep children..
22997 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22998 while (node.childNodes.length) {
22999 var cn = node.childNodes[0];
23000 node.removeChild(cn);
23001 node.parentNode.insertBefore(cn, node);
23003 node.parentNode.removeChild(node);
23004 this.iterateChildren(node, this.cleanWord);
23008 if (node.className.length) {
23010 var cn = node.className.split(/\W+/);
23012 Roo.each(cn, function(cls) {
23013 if (cls.match(/Mso[a-zA-Z]+/)) {
23018 node.className = cna.length ? cna.join(' ') : '';
23020 node.removeAttribute("class");
23024 if (node.hasAttribute("lang")) {
23025 node.removeAttribute("lang");
23028 if (node.hasAttribute("style")) {
23030 var styles = node.getAttribute("style").split(";");
23032 Roo.each(styles, function(s) {
23033 if (!s.match(/:/)) {
23036 var kv = s.split(":");
23037 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23040 // what ever is left... we allow.
23043 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23044 if (!nstyle.length) {
23045 node.removeAttribute('style');
23048 this.iterateChildren(node, this.cleanWord);
23054 * iterateChildren of a Node, calling fn each time, using this as the scole..
23055 * @param {DomNode} node node to iterate children of.
23056 * @param {Function} fn method of this class to call on each item.
23058 iterateChildren : function(node, fn)
23060 if (!node.childNodes.length) {
23063 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23064 fn.call(this, node.childNodes[i])
23070 * cleanTableWidths.
23072 * Quite often pasting from word etc.. results in tables with column and widths.
23073 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23076 cleanTableWidths : function(node)
23081 this.cleanTableWidths(this.doc.body);
23086 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23089 Roo.log(node.tagName);
23090 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23091 this.iterateChildren(node, this.cleanTableWidths);
23094 if (node.hasAttribute('width')) {
23095 node.removeAttribute('width');
23099 if (node.hasAttribute("style")) {
23102 var styles = node.getAttribute("style").split(";");
23104 Roo.each(styles, function(s) {
23105 if (!s.match(/:/)) {
23108 var kv = s.split(":");
23109 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23112 // what ever is left... we allow.
23115 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23116 if (!nstyle.length) {
23117 node.removeAttribute('style');
23121 this.iterateChildren(node, this.cleanTableWidths);
23129 domToHTML : function(currentElement, depth, nopadtext) {
23131 depth = depth || 0;
23132 nopadtext = nopadtext || false;
23134 if (!currentElement) {
23135 return this.domToHTML(this.doc.body);
23138 //Roo.log(currentElement);
23140 var allText = false;
23141 var nodeName = currentElement.nodeName;
23142 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23144 if (nodeName == '#text') {
23146 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23151 if (nodeName != 'BODY') {
23154 // Prints the node tagName, such as <A>, <IMG>, etc
23157 for(i = 0; i < currentElement.attributes.length;i++) {
23159 var aname = currentElement.attributes.item(i).name;
23160 if (!currentElement.attributes.item(i).value.length) {
23163 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23166 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23175 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23178 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23183 // Traverse the tree
23185 var currentElementChild = currentElement.childNodes.item(i);
23186 var allText = true;
23187 var innerHTML = '';
23189 while (currentElementChild) {
23190 // Formatting code (indent the tree so it looks nice on the screen)
23191 var nopad = nopadtext;
23192 if (lastnode == 'SPAN') {
23196 if (currentElementChild.nodeName == '#text') {
23197 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23198 toadd = nopadtext ? toadd : toadd.trim();
23199 if (!nopad && toadd.length > 80) {
23200 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23202 innerHTML += toadd;
23205 currentElementChild = currentElement.childNodes.item(i);
23211 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23213 // Recursively traverse the tree structure of the child node
23214 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23215 lastnode = currentElementChild.nodeName;
23217 currentElementChild=currentElement.childNodes.item(i);
23223 // The remaining code is mostly for formatting the tree
23224 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23229 ret+= "</"+tagName+">";
23235 applyBlacklists : function()
23237 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23238 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23242 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23243 if (b.indexOf(tag) > -1) {
23246 this.white.push(tag);
23250 Roo.each(w, function(tag) {
23251 if (b.indexOf(tag) > -1) {
23254 if (this.white.indexOf(tag) > -1) {
23257 this.white.push(tag);
23262 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23263 if (w.indexOf(tag) > -1) {
23266 this.black.push(tag);
23270 Roo.each(b, function(tag) {
23271 if (w.indexOf(tag) > -1) {
23274 if (this.black.indexOf(tag) > -1) {
23277 this.black.push(tag);
23282 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23283 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23287 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23288 if (b.indexOf(tag) > -1) {
23291 this.cwhite.push(tag);
23295 Roo.each(w, function(tag) {
23296 if (b.indexOf(tag) > -1) {
23299 if (this.cwhite.indexOf(tag) > -1) {
23302 this.cwhite.push(tag);
23307 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23308 if (w.indexOf(tag) > -1) {
23311 this.cblack.push(tag);
23315 Roo.each(b, function(tag) {
23316 if (w.indexOf(tag) > -1) {
23319 if (this.cblack.indexOf(tag) > -1) {
23322 this.cblack.push(tag);
23327 setStylesheets : function(stylesheets)
23329 if(typeof(stylesheets) == 'string'){
23330 Roo.get(this.iframe.contentDocument.head).createChild({
23332 rel : 'stylesheet',
23341 Roo.each(stylesheets, function(s) {
23346 Roo.get(_this.iframe.contentDocument.head).createChild({
23348 rel : 'stylesheet',
23357 removeStylesheets : function()
23361 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23366 setStyle : function(style)
23368 Roo.get(this.iframe.contentDocument.head).createChild({
23377 // hide stuff that is not compatible
23391 * @event specialkey
23395 * @cfg {String} fieldClass @hide
23398 * @cfg {String} focusClass @hide
23401 * @cfg {String} autoCreate @hide
23404 * @cfg {String} inputType @hide
23407 * @cfg {String} invalidClass @hide
23410 * @cfg {String} invalidText @hide
23413 * @cfg {String} msgFx @hide
23416 * @cfg {String} validateOnBlur @hide
23420 Roo.HtmlEditorCore.white = [
23421 'area', 'br', 'img', 'input', 'hr', 'wbr',
23423 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23424 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23425 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23426 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23427 'table', 'ul', 'xmp',
23429 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23432 'dir', 'menu', 'ol', 'ul', 'dl',
23438 Roo.HtmlEditorCore.black = [
23439 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23441 'base', 'basefont', 'bgsound', 'blink', 'body',
23442 'frame', 'frameset', 'head', 'html', 'ilayer',
23443 'iframe', 'layer', 'link', 'meta', 'object',
23444 'script', 'style' ,'title', 'xml' // clean later..
23446 Roo.HtmlEditorCore.clean = [
23447 'script', 'style', 'title', 'xml'
23449 Roo.HtmlEditorCore.remove = [
23454 Roo.HtmlEditorCore.ablack = [
23458 Roo.HtmlEditorCore.aclean = [
23459 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23463 Roo.HtmlEditorCore.pwhite= [
23464 'http', 'https', 'mailto'
23467 // white listed style attributes.
23468 Roo.HtmlEditorCore.cwhite= [
23469 // 'text-align', /// default is to allow most things..
23475 // black listed style attributes.
23476 Roo.HtmlEditorCore.cblack= [
23477 // 'font-size' -- this can be set by the project
23481 Roo.HtmlEditorCore.swapCodes =[
23500 * @class Roo.bootstrap.HtmlEditor
23501 * @extends Roo.bootstrap.TextArea
23502 * Bootstrap HtmlEditor class
23505 * Create a new HtmlEditor
23506 * @param {Object} config The config object
23509 Roo.bootstrap.HtmlEditor = function(config){
23510 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23511 if (!this.toolbars) {
23512 this.toolbars = [];
23515 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23518 * @event initialize
23519 * Fires when the editor is fully initialized (including the iframe)
23520 * @param {HtmlEditor} this
23525 * Fires when the editor is first receives the focus. Any insertion must wait
23526 * until after this event.
23527 * @param {HtmlEditor} this
23531 * @event beforesync
23532 * Fires before the textarea is updated with content from the editor iframe. Return false
23533 * to cancel the sync.
23534 * @param {HtmlEditor} this
23535 * @param {String} html
23539 * @event beforepush
23540 * Fires before the iframe editor is updated with content from the textarea. Return false
23541 * to cancel the push.
23542 * @param {HtmlEditor} this
23543 * @param {String} html
23548 * Fires when the textarea is updated with content from the editor iframe.
23549 * @param {HtmlEditor} this
23550 * @param {String} html
23555 * Fires when the iframe editor is updated with content from the textarea.
23556 * @param {HtmlEditor} this
23557 * @param {String} html
23561 * @event editmodechange
23562 * Fires when the editor switches edit modes
23563 * @param {HtmlEditor} this
23564 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23566 editmodechange: true,
23568 * @event editorevent
23569 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23570 * @param {HtmlEditor} this
23574 * @event firstfocus
23575 * Fires when on first focus - needed by toolbars..
23576 * @param {HtmlEditor} this
23581 * Auto save the htmlEditor value as a file into Events
23582 * @param {HtmlEditor} this
23586 * @event savedpreview
23587 * preview the saved version of htmlEditor
23588 * @param {HtmlEditor} this
23595 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23599 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23604 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23609 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23614 * @cfg {Number} height (in pixels)
23618 * @cfg {Number} width (in pixels)
23623 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23626 stylesheets: false,
23631 // private properties
23632 validationEvent : false,
23634 initialized : false,
23637 onFocus : Roo.emptyFn,
23639 hideMode:'offsets',
23641 tbContainer : false,
23645 toolbarContainer :function() {
23646 return this.wrap.select('.x-html-editor-tb',true).first();
23650 * Protected method that will not generally be called directly. It
23651 * is called when the editor creates its toolbar. Override this method if you need to
23652 * add custom toolbar buttons.
23653 * @param {HtmlEditor} editor
23655 createToolbar : function(){
23656 Roo.log('renewing');
23657 Roo.log("create toolbars");
23659 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23660 this.toolbars[0].render(this.toolbarContainer());
23664 // if (!editor.toolbars || !editor.toolbars.length) {
23665 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23668 // for (var i =0 ; i < editor.toolbars.length;i++) {
23669 // editor.toolbars[i] = Roo.factory(
23670 // typeof(editor.toolbars[i]) == 'string' ?
23671 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23672 // Roo.bootstrap.HtmlEditor);
23673 // editor.toolbars[i].init(editor);
23679 onRender : function(ct, position)
23681 // Roo.log("Call onRender: " + this.xtype);
23683 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23685 this.wrap = this.inputEl().wrap({
23686 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23689 this.editorcore.onRender(ct, position);
23691 if (this.resizable) {
23692 this.resizeEl = new Roo.Resizable(this.wrap, {
23696 minHeight : this.height,
23697 height: this.height,
23698 handles : this.resizable,
23701 resize : function(r, w, h) {
23702 _t.onResize(w,h); // -something
23708 this.createToolbar(this);
23711 if(!this.width && this.resizable){
23712 this.setSize(this.wrap.getSize());
23714 if (this.resizeEl) {
23715 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23716 // should trigger onReize..
23722 onResize : function(w, h)
23724 Roo.log('resize: ' +w + ',' + h );
23725 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23729 if(this.inputEl() ){
23730 if(typeof w == 'number'){
23731 var aw = w - this.wrap.getFrameWidth('lr');
23732 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23735 if(typeof h == 'number'){
23736 var tbh = -11; // fixme it needs to tool bar size!
23737 for (var i =0; i < this.toolbars.length;i++) {
23738 // fixme - ask toolbars for heights?
23739 tbh += this.toolbars[i].el.getHeight();
23740 //if (this.toolbars[i].footer) {
23741 // tbh += this.toolbars[i].footer.el.getHeight();
23749 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23750 ah -= 5; // knock a few pixes off for look..
23751 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23755 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23756 this.editorcore.onResize(ew,eh);
23761 * Toggles the editor between standard and source edit mode.
23762 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23764 toggleSourceEdit : function(sourceEditMode)
23766 this.editorcore.toggleSourceEdit(sourceEditMode);
23768 if(this.editorcore.sourceEditMode){
23769 Roo.log('editor - showing textarea');
23772 // Roo.log(this.syncValue());
23774 this.inputEl().removeClass(['hide', 'x-hidden']);
23775 this.inputEl().dom.removeAttribute('tabIndex');
23776 this.inputEl().focus();
23778 Roo.log('editor - hiding textarea');
23780 // Roo.log(this.pushValue());
23783 this.inputEl().addClass(['hide', 'x-hidden']);
23784 this.inputEl().dom.setAttribute('tabIndex', -1);
23785 //this.deferFocus();
23788 if(this.resizable){
23789 this.setSize(this.wrap.getSize());
23792 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23795 // private (for BoxComponent)
23796 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23798 // private (for BoxComponent)
23799 getResizeEl : function(){
23803 // private (for BoxComponent)
23804 getPositionEl : function(){
23809 initEvents : function(){
23810 this.originalValue = this.getValue();
23814 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23817 // markInvalid : Roo.emptyFn,
23819 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23822 // clearInvalid : Roo.emptyFn,
23824 setValue : function(v){
23825 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23826 this.editorcore.pushValue();
23831 deferFocus : function(){
23832 this.focus.defer(10, this);
23836 focus : function(){
23837 this.editorcore.focus();
23843 onDestroy : function(){
23849 for (var i =0; i < this.toolbars.length;i++) {
23850 // fixme - ask toolbars for heights?
23851 this.toolbars[i].onDestroy();
23854 this.wrap.dom.innerHTML = '';
23855 this.wrap.remove();
23860 onFirstFocus : function(){
23861 //Roo.log("onFirstFocus");
23862 this.editorcore.onFirstFocus();
23863 for (var i =0; i < this.toolbars.length;i++) {
23864 this.toolbars[i].onFirstFocus();
23870 syncValue : function()
23872 this.editorcore.syncValue();
23875 pushValue : function()
23877 this.editorcore.pushValue();
23881 // hide stuff that is not compatible
23895 * @event specialkey
23899 * @cfg {String} fieldClass @hide
23902 * @cfg {String} focusClass @hide
23905 * @cfg {String} autoCreate @hide
23908 * @cfg {String} inputType @hide
23911 * @cfg {String} invalidClass @hide
23914 * @cfg {String} invalidText @hide
23917 * @cfg {String} msgFx @hide
23920 * @cfg {String} validateOnBlur @hide
23929 Roo.namespace('Roo.bootstrap.htmleditor');
23931 * @class Roo.bootstrap.HtmlEditorToolbar1
23936 new Roo.bootstrap.HtmlEditor({
23939 new Roo.bootstrap.HtmlEditorToolbar1({
23940 disable : { fonts: 1 , format: 1, ..., ... , ...],
23946 * @cfg {Object} disable List of elements to disable..
23947 * @cfg {Array} btns List of additional buttons.
23951 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23954 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23957 Roo.apply(this, config);
23959 // default disabled, based on 'good practice'..
23960 this.disable = this.disable || {};
23961 Roo.applyIf(this.disable, {
23964 specialElements : true
23966 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23968 this.editor = config.editor;
23969 this.editorcore = config.editor.editorcore;
23971 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23973 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23974 // dont call parent... till later.
23976 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23981 editorcore : false,
23986 "h1","h2","h3","h4","h5","h6",
23988 "abbr", "acronym", "address", "cite", "samp", "var",
23992 onRender : function(ct, position)
23994 // Roo.log("Call onRender: " + this.xtype);
23996 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23998 this.el.dom.style.marginBottom = '0';
24000 var editorcore = this.editorcore;
24001 var editor= this.editor;
24004 var btn = function(id,cmd , toggle, handler, html){
24006 var event = toggle ? 'toggle' : 'click';
24011 xns: Roo.bootstrap,
24015 enableToggle:toggle !== false,
24017 pressed : toggle ? false : null,
24020 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24021 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24027 // var cb_box = function...
24032 xns: Roo.bootstrap,
24037 xns: Roo.bootstrap,
24041 Roo.each(this.formats, function(f) {
24042 style.menu.items.push({
24044 xns: Roo.bootstrap,
24045 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24050 editorcore.insertTag(this.tagname);
24057 children.push(style);
24059 btn('bold',false,true);
24060 btn('italic',false,true);
24061 btn('align-left', 'justifyleft',true);
24062 btn('align-center', 'justifycenter',true);
24063 btn('align-right' , 'justifyright',true);
24064 btn('link', false, false, function(btn) {
24065 //Roo.log("create link?");
24066 var url = prompt(this.createLinkText, this.defaultLinkValue);
24067 if(url && url != 'http:/'+'/'){
24068 this.editorcore.relayCmd('createlink', url);
24071 btn('list','insertunorderedlist',true);
24072 btn('pencil', false,true, function(btn){
24074 this.toggleSourceEdit(btn.pressed);
24077 if (this.editor.btns.length > 0) {
24078 for (var i = 0; i<this.editor.btns.length; i++) {
24079 children.push(this.editor.btns[i]);
24087 xns: Roo.bootstrap,
24092 xns: Roo.bootstrap,
24097 cog.menu.items.push({
24099 xns: Roo.bootstrap,
24100 html : Clean styles,
24105 editorcore.insertTag(this.tagname);
24114 this.xtype = 'NavSimplebar';
24116 for(var i=0;i< children.length;i++) {
24118 this.buttons.add(this.addxtypeChild(children[i]));
24122 editor.on('editorevent', this.updateToolbar, this);
24124 onBtnClick : function(id)
24126 this.editorcore.relayCmd(id);
24127 this.editorcore.focus();
24131 * Protected method that will not generally be called directly. It triggers
24132 * a toolbar update by reading the markup state of the current selection in the editor.
24134 updateToolbar: function(){
24136 if(!this.editorcore.activated){
24137 this.editor.onFirstFocus(); // is this neeed?
24141 var btns = this.buttons;
24142 var doc = this.editorcore.doc;
24143 btns.get('bold').setActive(doc.queryCommandState('bold'));
24144 btns.get('italic').setActive(doc.queryCommandState('italic'));
24145 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24147 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24148 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24149 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24151 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24152 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24155 var ans = this.editorcore.getAllAncestors();
24156 if (this.formatCombo) {
24159 var store = this.formatCombo.store;
24160 this.formatCombo.setValue("");
24161 for (var i =0; i < ans.length;i++) {
24162 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24164 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24172 // hides menus... - so this cant be on a menu...
24173 Roo.bootstrap.MenuMgr.hideAll();
24175 Roo.bootstrap.MenuMgr.hideAll();
24176 //this.editorsyncValue();
24178 onFirstFocus: function() {
24179 this.buttons.each(function(item){
24183 toggleSourceEdit : function(sourceEditMode){
24186 if(sourceEditMode){
24187 Roo.log("disabling buttons");
24188 this.buttons.each( function(item){
24189 if(item.cmd != 'pencil'){
24195 Roo.log("enabling buttons");
24196 if(this.editorcore.initialized){
24197 this.buttons.each( function(item){
24203 Roo.log("calling toggole on editor");
24204 // tell the editor that it's been pressed..
24205 this.editor.toggleSourceEdit(sourceEditMode);
24215 * @class Roo.bootstrap.Table.AbstractSelectionModel
24216 * @extends Roo.util.Observable
24217 * Abstract base class for grid SelectionModels. It provides the interface that should be
24218 * implemented by descendant classes. This class should not be directly instantiated.
24221 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24222 this.locked = false;
24223 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24227 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24228 /** @ignore Called by the grid automatically. Do not call directly. */
24229 init : function(grid){
24235 * Locks the selections.
24238 this.locked = true;
24242 * Unlocks the selections.
24244 unlock : function(){
24245 this.locked = false;
24249 * Returns true if the selections are locked.
24250 * @return {Boolean}
24252 isLocked : function(){
24253 return this.locked;
24257 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24258 * @class Roo.bootstrap.Table.RowSelectionModel
24259 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24260 * It supports multiple selections and keyboard selection/navigation.
24262 * @param {Object} config
24265 Roo.bootstrap.Table.RowSelectionModel = function(config){
24266 Roo.apply(this, config);
24267 this.selections = new Roo.util.MixedCollection(false, function(o){
24272 this.lastActive = false;
24276 * @event selectionchange
24277 * Fires when the selection changes
24278 * @param {SelectionModel} this
24280 "selectionchange" : true,
24282 * @event afterselectionchange
24283 * Fires after the selection changes (eg. by key press or clicking)
24284 * @param {SelectionModel} this
24286 "afterselectionchange" : true,
24288 * @event beforerowselect
24289 * Fires when a row is selected being selected, return false to cancel.
24290 * @param {SelectionModel} this
24291 * @param {Number} rowIndex The selected index
24292 * @param {Boolean} keepExisting False if other selections will be cleared
24294 "beforerowselect" : true,
24297 * Fires when a row is selected.
24298 * @param {SelectionModel} this
24299 * @param {Number} rowIndex The selected index
24300 * @param {Roo.data.Record} r The record
24302 "rowselect" : true,
24304 * @event rowdeselect
24305 * Fires when a row is deselected.
24306 * @param {SelectionModel} this
24307 * @param {Number} rowIndex The selected index
24309 "rowdeselect" : true
24311 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24312 this.locked = false;
24315 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24317 * @cfg {Boolean} singleSelect
24318 * True to allow selection of only one row at a time (defaults to false)
24320 singleSelect : false,
24323 initEvents : function()
24326 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24327 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24328 //}else{ // allow click to work like normal
24329 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24331 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24332 this.grid.on("rowclick", this.handleMouseDown, this);
24334 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24335 "up" : function(e){
24337 this.selectPrevious(e.shiftKey);
24338 }else if(this.last !== false && this.lastActive !== false){
24339 var last = this.last;
24340 this.selectRange(this.last, this.lastActive-1);
24341 this.grid.getView().focusRow(this.lastActive);
24342 if(last !== false){
24346 this.selectFirstRow();
24348 this.fireEvent("afterselectionchange", this);
24350 "down" : function(e){
24352 this.selectNext(e.shiftKey);
24353 }else if(this.last !== false && this.lastActive !== false){
24354 var last = this.last;
24355 this.selectRange(this.last, this.lastActive+1);
24356 this.grid.getView().focusRow(this.lastActive);
24357 if(last !== false){
24361 this.selectFirstRow();
24363 this.fireEvent("afterselectionchange", this);
24367 this.grid.store.on('load', function(){
24368 this.selections.clear();
24371 var view = this.grid.view;
24372 view.on("refresh", this.onRefresh, this);
24373 view.on("rowupdated", this.onRowUpdated, this);
24374 view.on("rowremoved", this.onRemove, this);
24379 onRefresh : function()
24381 var ds = this.grid.store, i, v = this.grid.view;
24382 var s = this.selections;
24383 s.each(function(r){
24384 if((i = ds.indexOfId(r.id)) != -1){
24393 onRemove : function(v, index, r){
24394 this.selections.remove(r);
24398 onRowUpdated : function(v, index, r){
24399 if(this.isSelected(r)){
24400 v.onRowSelect(index);
24406 * @param {Array} records The records to select
24407 * @param {Boolean} keepExisting (optional) True to keep existing selections
24409 selectRecords : function(records, keepExisting)
24412 this.clearSelections();
24414 var ds = this.grid.store;
24415 for(var i = 0, len = records.length; i < len; i++){
24416 this.selectRow(ds.indexOf(records[i]), true);
24421 * Gets the number of selected rows.
24424 getCount : function(){
24425 return this.selections.length;
24429 * Selects the first row in the grid.
24431 selectFirstRow : function(){
24436 * Select the last row.
24437 * @param {Boolean} keepExisting (optional) True to keep existing selections
24439 selectLastRow : function(keepExisting){
24440 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24441 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24445 * Selects the row immediately following the last selected row.
24446 * @param {Boolean} keepExisting (optional) True to keep existing selections
24448 selectNext : function(keepExisting)
24450 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24451 this.selectRow(this.last+1, keepExisting);
24452 this.grid.getView().focusRow(this.last);
24457 * Selects the row that precedes the last selected row.
24458 * @param {Boolean} keepExisting (optional) True to keep existing selections
24460 selectPrevious : function(keepExisting){
24462 this.selectRow(this.last-1, keepExisting);
24463 this.grid.getView().focusRow(this.last);
24468 * Returns the selected records
24469 * @return {Array} Array of selected records
24471 getSelections : function(){
24472 return [].concat(this.selections.items);
24476 * Returns the first selected record.
24479 getSelected : function(){
24480 return this.selections.itemAt(0);
24485 * Clears all selections.
24487 clearSelections : function(fast)
24493 var ds = this.grid.store;
24494 var s = this.selections;
24495 s.each(function(r){
24496 this.deselectRow(ds.indexOfId(r.id));
24500 this.selections.clear();
24507 * Selects all rows.
24509 selectAll : function(){
24513 this.selections.clear();
24514 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24515 this.selectRow(i, true);
24520 * Returns True if there is a selection.
24521 * @return {Boolean}
24523 hasSelection : function(){
24524 return this.selections.length > 0;
24528 * Returns True if the specified row is selected.
24529 * @param {Number/Record} record The record or index of the record to check
24530 * @return {Boolean}
24532 isSelected : function(index){
24533 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24534 return (r && this.selections.key(r.id) ? true : false);
24538 * Returns True if the specified record id is selected.
24539 * @param {String} id The id of record to check
24540 * @return {Boolean}
24542 isIdSelected : function(id){
24543 return (this.selections.key(id) ? true : false);
24548 handleMouseDBClick : function(e, t){
24552 handleMouseDown : function(e, t)
24554 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24555 if(this.isLocked() || rowIndex < 0 ){
24558 if(e.shiftKey && this.last !== false){
24559 var last = this.last;
24560 this.selectRange(last, rowIndex, e.ctrlKey);
24561 this.last = last; // reset the last
24565 var isSelected = this.isSelected(rowIndex);
24566 //Roo.log("select row:" + rowIndex);
24568 this.deselectRow(rowIndex);
24570 this.selectRow(rowIndex, true);
24574 if(e.button !== 0 && isSelected){
24575 alert('rowIndex 2: ' + rowIndex);
24576 view.focusRow(rowIndex);
24577 }else if(e.ctrlKey && isSelected){
24578 this.deselectRow(rowIndex);
24579 }else if(!isSelected){
24580 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24581 view.focusRow(rowIndex);
24585 this.fireEvent("afterselectionchange", this);
24588 handleDragableRowClick : function(grid, rowIndex, e)
24590 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24591 this.selectRow(rowIndex, false);
24592 grid.view.focusRow(rowIndex);
24593 this.fireEvent("afterselectionchange", this);
24598 * Selects multiple rows.
24599 * @param {Array} rows Array of the indexes of the row to select
24600 * @param {Boolean} keepExisting (optional) True to keep existing selections
24602 selectRows : function(rows, keepExisting){
24604 this.clearSelections();
24606 for(var i = 0, len = rows.length; i < len; i++){
24607 this.selectRow(rows[i], true);
24612 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24613 * @param {Number} startRow The index of the first row in the range
24614 * @param {Number} endRow The index of the last row in the range
24615 * @param {Boolean} keepExisting (optional) True to retain existing selections
24617 selectRange : function(startRow, endRow, keepExisting){
24622 this.clearSelections();
24624 if(startRow <= endRow){
24625 for(var i = startRow; i <= endRow; i++){
24626 this.selectRow(i, true);
24629 for(var i = startRow; i >= endRow; i--){
24630 this.selectRow(i, true);
24636 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24637 * @param {Number} startRow The index of the first row in the range
24638 * @param {Number} endRow The index of the last row in the range
24640 deselectRange : function(startRow, endRow, preventViewNotify){
24644 for(var i = startRow; i <= endRow; i++){
24645 this.deselectRow(i, preventViewNotify);
24651 * @param {Number} row The index of the row to select
24652 * @param {Boolean} keepExisting (optional) True to keep existing selections
24654 selectRow : function(index, keepExisting, preventViewNotify)
24656 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24659 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24660 if(!keepExisting || this.singleSelect){
24661 this.clearSelections();
24664 var r = this.grid.store.getAt(index);
24665 //console.log('selectRow - record id :' + r.id);
24667 this.selections.add(r);
24668 this.last = this.lastActive = index;
24669 if(!preventViewNotify){
24670 var proxy = new Roo.Element(
24671 this.grid.getRowDom(index)
24673 proxy.addClass('bg-info info');
24675 this.fireEvent("rowselect", this, index, r);
24676 this.fireEvent("selectionchange", this);
24682 * @param {Number} row The index of the row to deselect
24684 deselectRow : function(index, preventViewNotify)
24689 if(this.last == index){
24692 if(this.lastActive == index){
24693 this.lastActive = false;
24696 var r = this.grid.store.getAt(index);
24701 this.selections.remove(r);
24702 //.console.log('deselectRow - record id :' + r.id);
24703 if(!preventViewNotify){
24705 var proxy = new Roo.Element(
24706 this.grid.getRowDom(index)
24708 proxy.removeClass('bg-info info');
24710 this.fireEvent("rowdeselect", this, index);
24711 this.fireEvent("selectionchange", this);
24715 restoreLast : function(){
24717 this.last = this._last;
24722 acceptsNav : function(row, col, cm){
24723 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24727 onEditorKey : function(field, e){
24728 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24733 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24735 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24737 }else if(k == e.ENTER && !e.ctrlKey){
24741 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24743 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24745 }else if(k == e.ESC){
24749 g.startEditing(newCell[0], newCell[1]);
24755 * Ext JS Library 1.1.1
24756 * Copyright(c) 2006-2007, Ext JS, LLC.
24758 * Originally Released Under LGPL - original licence link has changed is not relivant.
24761 * <script type="text/javascript">
24765 * @class Roo.bootstrap.PagingToolbar
24766 * @extends Roo.bootstrap.NavSimplebar
24767 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24769 * Create a new PagingToolbar
24770 * @param {Object} config The config object
24771 * @param {Roo.data.Store} store
24773 Roo.bootstrap.PagingToolbar = function(config)
24775 // old args format still supported... - xtype is prefered..
24776 // created from xtype...
24778 this.ds = config.dataSource;
24780 if (config.store && !this.ds) {
24781 this.store= Roo.factory(config.store, Roo.data);
24782 this.ds = this.store;
24783 this.ds.xmodule = this.xmodule || false;
24786 this.toolbarItems = [];
24787 if (config.items) {
24788 this.toolbarItems = config.items;
24791 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24796 this.bind(this.ds);
24799 if (Roo.bootstrap.version == 4) {
24800 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24802 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24807 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24809 * @cfg {Roo.data.Store} dataSource
24810 * The underlying data store providing the paged data
24813 * @cfg {String/HTMLElement/Element} container
24814 * container The id or element that will contain the toolbar
24817 * @cfg {Boolean} displayInfo
24818 * True to display the displayMsg (defaults to false)
24821 * @cfg {Number} pageSize
24822 * The number of records to display per page (defaults to 20)
24826 * @cfg {String} displayMsg
24827 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24829 displayMsg : 'Displaying {0} - {1} of {2}',
24831 * @cfg {String} emptyMsg
24832 * The message to display when no records are found (defaults to "No data to display")
24834 emptyMsg : 'No data to display',
24836 * Customizable piece of the default paging text (defaults to "Page")
24839 beforePageText : "Page",
24841 * Customizable piece of the default paging text (defaults to "of %0")
24844 afterPageText : "of {0}",
24846 * Customizable piece of the default paging text (defaults to "First Page")
24849 firstText : "First Page",
24851 * Customizable piece of the default paging text (defaults to "Previous Page")
24854 prevText : "Previous Page",
24856 * Customizable piece of the default paging text (defaults to "Next Page")
24859 nextText : "Next Page",
24861 * Customizable piece of the default paging text (defaults to "Last Page")
24864 lastText : "Last Page",
24866 * Customizable piece of the default paging text (defaults to "Refresh")
24869 refreshText : "Refresh",
24873 onRender : function(ct, position)
24875 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24876 this.navgroup.parentId = this.id;
24877 this.navgroup.onRender(this.el, null);
24878 // add the buttons to the navgroup
24880 if(this.displayInfo){
24881 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24882 this.displayEl = this.el.select('.x-paging-info', true).first();
24883 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24884 // this.displayEl = navel.el.select('span',true).first();
24890 Roo.each(_this.buttons, function(e){ // this might need to use render????
24891 Roo.factory(e).render(_this.el);
24895 Roo.each(_this.toolbarItems, function(e) {
24896 _this.navgroup.addItem(e);
24900 this.first = this.navgroup.addItem({
24901 tooltip: this.firstText,
24902 cls: "prev btn-outline-secondary",
24903 html : ' <i class="fa fa-step-backward"></i>',
24905 preventDefault: true,
24906 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24909 this.prev = this.navgroup.addItem({
24910 tooltip: this.prevText,
24911 cls: "prev btn-outline-secondary",
24912 html : ' <i class="fa fa-backward"></i>',
24914 preventDefault: true,
24915 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24917 //this.addSeparator();
24920 var field = this.navgroup.addItem( {
24922 cls : 'x-paging-position btn-outline-secondary',
24924 html : this.beforePageText +
24925 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24926 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24929 this.field = field.el.select('input', true).first();
24930 this.field.on("keydown", this.onPagingKeydown, this);
24931 this.field.on("focus", function(){this.dom.select();});
24934 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24935 //this.field.setHeight(18);
24936 //this.addSeparator();
24937 this.next = this.navgroup.addItem({
24938 tooltip: this.nextText,
24939 cls: "next btn-outline-secondary",
24940 html : ' <i class="fa fa-forward"></i>',
24942 preventDefault: true,
24943 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24945 this.last = this.navgroup.addItem({
24946 tooltip: this.lastText,
24947 html : ' <i class="fa fa-step-forward"></i>',
24948 cls: "next btn-outline-secondary",
24950 preventDefault: true,
24951 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24953 //this.addSeparator();
24954 this.loading = this.navgroup.addItem({
24955 tooltip: this.refreshText,
24956 cls: "btn-outline-secondary",
24957 html : ' <i class="fa fa-refresh"></i>',
24958 preventDefault: true,
24959 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24965 updateInfo : function(){
24966 if(this.displayEl){
24967 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24968 var msg = count == 0 ?
24972 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24974 this.displayEl.update(msg);
24979 onLoad : function(ds, r, o)
24981 this.cursor = o.params.start ? o.params.start : 0;
24983 var d = this.getPageData(),
24988 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24989 this.field.dom.value = ap;
24990 this.first.setDisabled(ap == 1);
24991 this.prev.setDisabled(ap == 1);
24992 this.next.setDisabled(ap == ps);
24993 this.last.setDisabled(ap == ps);
24994 this.loading.enable();
24999 getPageData : function(){
25000 var total = this.ds.getTotalCount();
25003 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25004 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25009 onLoadError : function(){
25010 this.loading.enable();
25014 onPagingKeydown : function(e){
25015 var k = e.getKey();
25016 var d = this.getPageData();
25018 var v = this.field.dom.value, pageNum;
25019 if(!v || isNaN(pageNum = parseInt(v, 10))){
25020 this.field.dom.value = d.activePage;
25023 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25024 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25027 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))
25029 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25030 this.field.dom.value = pageNum;
25031 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25034 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25036 var v = this.field.dom.value, pageNum;
25037 var increment = (e.shiftKey) ? 10 : 1;
25038 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25041 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25042 this.field.dom.value = d.activePage;
25045 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25047 this.field.dom.value = parseInt(v, 10) + increment;
25048 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25049 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25056 beforeLoad : function(){
25058 this.loading.disable();
25063 onClick : function(which){
25072 ds.load({params:{start: 0, limit: this.pageSize}});
25075 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25078 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25081 var total = ds.getTotalCount();
25082 var extra = total % this.pageSize;
25083 var lastStart = extra ? (total - extra) : total-this.pageSize;
25084 ds.load({params:{start: lastStart, limit: this.pageSize}});
25087 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25093 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25094 * @param {Roo.data.Store} store The data store to unbind
25096 unbind : function(ds){
25097 ds.un("beforeload", this.beforeLoad, this);
25098 ds.un("load", this.onLoad, this);
25099 ds.un("loadexception", this.onLoadError, this);
25100 ds.un("remove", this.updateInfo, this);
25101 ds.un("add", this.updateInfo, this);
25102 this.ds = undefined;
25106 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25107 * @param {Roo.data.Store} store The data store to bind
25109 bind : function(ds){
25110 ds.on("beforeload", this.beforeLoad, this);
25111 ds.on("load", this.onLoad, this);
25112 ds.on("loadexception", this.onLoadError, this);
25113 ds.on("remove", this.updateInfo, this);
25114 ds.on("add", this.updateInfo, this);
25125 * @class Roo.bootstrap.MessageBar
25126 * @extends Roo.bootstrap.Component
25127 * Bootstrap MessageBar class
25128 * @cfg {String} html contents of the MessageBar
25129 * @cfg {String} weight (info | success | warning | danger) default info
25130 * @cfg {String} beforeClass insert the bar before the given class
25131 * @cfg {Boolean} closable (true | false) default false
25132 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25135 * Create a new Element
25136 * @param {Object} config The config object
25139 Roo.bootstrap.MessageBar = function(config){
25140 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25143 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25149 beforeClass: 'bootstrap-sticky-wrap',
25151 getAutoCreate : function(){
25155 cls: 'alert alert-dismissable alert-' + this.weight,
25160 html: this.html || ''
25166 cfg.cls += ' alert-messages-fixed';
25180 onRender : function(ct, position)
25182 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25185 var cfg = Roo.apply({}, this.getAutoCreate());
25189 cfg.cls += ' ' + this.cls;
25192 cfg.style = this.style;
25194 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25196 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25199 this.el.select('>button.close').on('click', this.hide, this);
25205 if (!this.rendered) {
25211 this.fireEvent('show', this);
25217 if (!this.rendered) {
25223 this.fireEvent('hide', this);
25226 update : function()
25228 // var e = this.el.dom.firstChild;
25230 // if(this.closable){
25231 // e = e.nextSibling;
25234 // e.data = this.html || '';
25236 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25252 * @class Roo.bootstrap.Graph
25253 * @extends Roo.bootstrap.Component
25254 * Bootstrap Graph class
25258 @cfg {String} graphtype bar | vbar | pie
25259 @cfg {number} g_x coodinator | centre x (pie)
25260 @cfg {number} g_y coodinator | centre y (pie)
25261 @cfg {number} g_r radius (pie)
25262 @cfg {number} g_height height of the chart (respected by all elements in the set)
25263 @cfg {number} g_width width of the chart (respected by all elements in the set)
25264 @cfg {Object} title The title of the chart
25267 -opts (object) options for the chart
25269 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25270 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25272 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.
25273 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25275 o stretch (boolean)
25277 -opts (object) options for the pie
25280 o startAngle (number)
25281 o endAngle (number)
25285 * Create a new Input
25286 * @param {Object} config The config object
25289 Roo.bootstrap.Graph = function(config){
25290 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25296 * The img click event for the img.
25297 * @param {Roo.EventObject} e
25303 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25314 //g_colors: this.colors,
25321 getAutoCreate : function(){
25332 onRender : function(ct,position){
25335 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25337 if (typeof(Raphael) == 'undefined') {
25338 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25342 this.raphael = Raphael(this.el.dom);
25344 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25345 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25346 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25347 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25349 r.text(160, 10, "Single Series Chart").attr(txtattr);
25350 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25351 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25352 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25354 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25355 r.barchart(330, 10, 300, 220, data1);
25356 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25357 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25360 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25361 // r.barchart(30, 30, 560, 250, xdata, {
25362 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25363 // axis : "0 0 1 1",
25364 // axisxlabels : xdata
25365 // //yvalues : cols,
25368 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25370 // this.load(null,xdata,{
25371 // axis : "0 0 1 1",
25372 // axisxlabels : xdata
25377 load : function(graphtype,xdata,opts)
25379 this.raphael.clear();
25381 graphtype = this.graphtype;
25386 var r = this.raphael,
25387 fin = function () {
25388 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25390 fout = function () {
25391 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25393 pfin = function() {
25394 this.sector.stop();
25395 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25398 this.label[0].stop();
25399 this.label[0].attr({ r: 7.5 });
25400 this.label[1].attr({ "font-weight": 800 });
25403 pfout = function() {
25404 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25407 this.label[0].animate({ r: 5 }, 500, "bounce");
25408 this.label[1].attr({ "font-weight": 400 });
25414 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25417 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25420 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25421 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25423 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25430 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25435 setTitle: function(o)
25440 initEvents: function() {
25443 this.el.on('click', this.onClick, this);
25447 onClick : function(e)
25449 Roo.log('img onclick');
25450 this.fireEvent('click', this, e);
25462 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25465 * @class Roo.bootstrap.dash.NumberBox
25466 * @extends Roo.bootstrap.Component
25467 * Bootstrap NumberBox class
25468 * @cfg {String} headline Box headline
25469 * @cfg {String} content Box content
25470 * @cfg {String} icon Box icon
25471 * @cfg {String} footer Footer text
25472 * @cfg {String} fhref Footer href
25475 * Create a new NumberBox
25476 * @param {Object} config The config object
25480 Roo.bootstrap.dash.NumberBox = function(config){
25481 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25485 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25494 getAutoCreate : function(){
25498 cls : 'small-box ',
25506 cls : 'roo-headline',
25507 html : this.headline
25511 cls : 'roo-content',
25512 html : this.content
25526 cls : 'ion ' + this.icon
25535 cls : 'small-box-footer',
25536 href : this.fhref || '#',
25540 cfg.cn.push(footer);
25547 onRender : function(ct,position){
25548 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25555 setHeadline: function (value)
25557 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25560 setFooter: function (value, href)
25562 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25565 this.el.select('a.small-box-footer',true).first().attr('href', href);
25570 setContent: function (value)
25572 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25575 initEvents: function()
25589 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25592 * @class Roo.bootstrap.dash.TabBox
25593 * @extends Roo.bootstrap.Component
25594 * Bootstrap TabBox class
25595 * @cfg {String} title Title of the TabBox
25596 * @cfg {String} icon Icon of the TabBox
25597 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25598 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25601 * Create a new TabBox
25602 * @param {Object} config The config object
25606 Roo.bootstrap.dash.TabBox = function(config){
25607 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25612 * When a pane is added
25613 * @param {Roo.bootstrap.dash.TabPane} pane
25617 * @event activatepane
25618 * When a pane is activated
25619 * @param {Roo.bootstrap.dash.TabPane} pane
25621 "activatepane" : true
25629 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25634 tabScrollable : false,
25636 getChildContainer : function()
25638 return this.el.select('.tab-content', true).first();
25641 getAutoCreate : function(){
25645 cls: 'pull-left header',
25653 cls: 'fa ' + this.icon
25659 cls: 'nav nav-tabs pull-right',
25665 if(this.tabScrollable){
25672 cls: 'nav nav-tabs pull-right',
25683 cls: 'nav-tabs-custom',
25688 cls: 'tab-content no-padding',
25696 initEvents : function()
25698 //Roo.log('add add pane handler');
25699 this.on('addpane', this.onAddPane, this);
25702 * Updates the box title
25703 * @param {String} html to set the title to.
25705 setTitle : function(value)
25707 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25709 onAddPane : function(pane)
25711 this.panes.push(pane);
25712 //Roo.log('addpane');
25714 // tabs are rendere left to right..
25715 if(!this.showtabs){
25719 var ctr = this.el.select('.nav-tabs', true).first();
25722 var existing = ctr.select('.nav-tab',true);
25723 var qty = existing.getCount();;
25726 var tab = ctr.createChild({
25728 cls : 'nav-tab' + (qty ? '' : ' active'),
25736 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25739 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25741 pane.el.addClass('active');
25746 onTabClick : function(ev,un,ob,pane)
25748 //Roo.log('tab - prev default');
25749 ev.preventDefault();
25752 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25753 pane.tab.addClass('active');
25754 //Roo.log(pane.title);
25755 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25756 // technically we should have a deactivate event.. but maybe add later.
25757 // and it should not de-activate the selected tab...
25758 this.fireEvent('activatepane', pane);
25759 pane.el.addClass('active');
25760 pane.fireEvent('activate');
25765 getActivePane : function()
25768 Roo.each(this.panes, function(p) {
25769 if(p.el.hasClass('active')){
25790 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25792 * @class Roo.bootstrap.TabPane
25793 * @extends Roo.bootstrap.Component
25794 * Bootstrap TabPane class
25795 * @cfg {Boolean} active (false | true) Default false
25796 * @cfg {String} title title of panel
25800 * Create a new TabPane
25801 * @param {Object} config The config object
25804 Roo.bootstrap.dash.TabPane = function(config){
25805 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25811 * When a pane is activated
25812 * @param {Roo.bootstrap.dash.TabPane} pane
25819 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25824 // the tabBox that this is attached to.
25827 getAutoCreate : function()
25835 cfg.cls += ' active';
25840 initEvents : function()
25842 //Roo.log('trigger add pane handler');
25843 this.parent().fireEvent('addpane', this)
25847 * Updates the tab title
25848 * @param {String} html to set the title to.
25850 setTitle: function(str)
25856 this.tab.select('a', true).first().dom.innerHTML = str;
25873 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25876 * @class Roo.bootstrap.menu.Menu
25877 * @extends Roo.bootstrap.Component
25878 * Bootstrap Menu class - container for Menu
25879 * @cfg {String} html Text of the menu
25880 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25881 * @cfg {String} icon Font awesome icon
25882 * @cfg {String} pos Menu align to (top | bottom) default bottom
25886 * Create a new Menu
25887 * @param {Object} config The config object
25891 Roo.bootstrap.menu.Menu = function(config){
25892 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25896 * @event beforeshow
25897 * Fires before this menu is displayed
25898 * @param {Roo.bootstrap.menu.Menu} this
25902 * @event beforehide
25903 * Fires before this menu is hidden
25904 * @param {Roo.bootstrap.menu.Menu} this
25909 * Fires after this menu is displayed
25910 * @param {Roo.bootstrap.menu.Menu} this
25915 * Fires after this menu is hidden
25916 * @param {Roo.bootstrap.menu.Menu} this
25921 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25922 * @param {Roo.bootstrap.menu.Menu} this
25923 * @param {Roo.EventObject} e
25930 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25934 weight : 'default',
25939 getChildContainer : function() {
25940 if(this.isSubMenu){
25944 return this.el.select('ul.dropdown-menu', true).first();
25947 getAutoCreate : function()
25952 cls : 'roo-menu-text',
25960 cls : 'fa ' + this.icon
25971 cls : 'dropdown-button btn btn-' + this.weight,
25976 cls : 'dropdown-toggle btn btn-' + this.weight,
25986 cls : 'dropdown-menu'
25992 if(this.pos == 'top'){
25993 cfg.cls += ' dropup';
25996 if(this.isSubMenu){
25999 cls : 'dropdown-menu'
26006 onRender : function(ct, position)
26008 this.isSubMenu = ct.hasClass('dropdown-submenu');
26010 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26013 initEvents : function()
26015 if(this.isSubMenu){
26019 this.hidden = true;
26021 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26022 this.triggerEl.on('click', this.onTriggerPress, this);
26024 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26025 this.buttonEl.on('click', this.onClick, this);
26031 if(this.isSubMenu){
26035 return this.el.select('ul.dropdown-menu', true).first();
26038 onClick : function(e)
26040 this.fireEvent("click", this, e);
26043 onTriggerPress : function(e)
26045 if (this.isVisible()) {
26052 isVisible : function(){
26053 return !this.hidden;
26058 this.fireEvent("beforeshow", this);
26060 this.hidden = false;
26061 this.el.addClass('open');
26063 Roo.get(document).on("mouseup", this.onMouseUp, this);
26065 this.fireEvent("show", this);
26072 this.fireEvent("beforehide", this);
26074 this.hidden = true;
26075 this.el.removeClass('open');
26077 Roo.get(document).un("mouseup", this.onMouseUp);
26079 this.fireEvent("hide", this);
26082 onMouseUp : function()
26096 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26099 * @class Roo.bootstrap.menu.Item
26100 * @extends Roo.bootstrap.Component
26101 * Bootstrap MenuItem class
26102 * @cfg {Boolean} submenu (true | false) default false
26103 * @cfg {String} html text of the item
26104 * @cfg {String} href the link
26105 * @cfg {Boolean} disable (true | false) default false
26106 * @cfg {Boolean} preventDefault (true | false) default true
26107 * @cfg {String} icon Font awesome icon
26108 * @cfg {String} pos Submenu align to (left | right) default right
26112 * Create a new Item
26113 * @param {Object} config The config object
26117 Roo.bootstrap.menu.Item = function(config){
26118 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26122 * Fires when the mouse is hovering over this menu
26123 * @param {Roo.bootstrap.menu.Item} this
26124 * @param {Roo.EventObject} e
26129 * Fires when the mouse exits this menu
26130 * @param {Roo.bootstrap.menu.Item} this
26131 * @param {Roo.EventObject} e
26137 * The raw click event for the entire grid.
26138 * @param {Roo.EventObject} e
26144 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26149 preventDefault: true,
26154 getAutoCreate : function()
26159 cls : 'roo-menu-item-text',
26167 cls : 'fa ' + this.icon
26176 href : this.href || '#',
26183 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26187 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26189 if(this.pos == 'left'){
26190 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26197 initEvents : function()
26199 this.el.on('mouseover', this.onMouseOver, this);
26200 this.el.on('mouseout', this.onMouseOut, this);
26202 this.el.select('a', true).first().on('click', this.onClick, this);
26206 onClick : function(e)
26208 if(this.preventDefault){
26209 e.preventDefault();
26212 this.fireEvent("click", this, e);
26215 onMouseOver : function(e)
26217 if(this.submenu && this.pos == 'left'){
26218 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26221 this.fireEvent("mouseover", this, e);
26224 onMouseOut : function(e)
26226 this.fireEvent("mouseout", this, e);
26238 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26241 * @class Roo.bootstrap.menu.Separator
26242 * @extends Roo.bootstrap.Component
26243 * Bootstrap Separator class
26246 * Create a new Separator
26247 * @param {Object} config The config object
26251 Roo.bootstrap.menu.Separator = function(config){
26252 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26255 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26257 getAutoCreate : function(){
26278 * @class Roo.bootstrap.Tooltip
26279 * Bootstrap Tooltip class
26280 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26281 * to determine which dom element triggers the tooltip.
26283 * It needs to add support for additional attributes like tooltip-position
26286 * Create a new Toolti
26287 * @param {Object} config The config object
26290 Roo.bootstrap.Tooltip = function(config){
26291 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26293 this.alignment = Roo.bootstrap.Tooltip.alignment;
26295 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26296 this.alignment = config.alignment;
26301 Roo.apply(Roo.bootstrap.Tooltip, {
26303 * @function init initialize tooltip monitoring.
26307 currentTip : false,
26308 currentRegion : false,
26314 Roo.get(document).on('mouseover', this.enter ,this);
26315 Roo.get(document).on('mouseout', this.leave, this);
26318 this.currentTip = new Roo.bootstrap.Tooltip();
26321 enter : function(ev)
26323 var dom = ev.getTarget();
26325 //Roo.log(['enter',dom]);
26326 var el = Roo.fly(dom);
26327 if (this.currentEl) {
26329 //Roo.log(this.currentEl);
26330 //Roo.log(this.currentEl.contains(dom));
26331 if (this.currentEl == el) {
26334 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26340 if (this.currentTip.el) {
26341 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26345 if(!el || el.dom == document){
26351 // you can not look for children, as if el is the body.. then everythign is the child..
26352 if (!el.attr('tooltip')) { //
26353 if (!el.select("[tooltip]").elements.length) {
26356 // is the mouse over this child...?
26357 bindEl = el.select("[tooltip]").first();
26358 var xy = ev.getXY();
26359 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26360 //Roo.log("not in region.");
26363 //Roo.log("child element over..");
26366 this.currentEl = bindEl;
26367 this.currentTip.bind(bindEl);
26368 this.currentRegion = Roo.lib.Region.getRegion(dom);
26369 this.currentTip.enter();
26372 leave : function(ev)
26374 var dom = ev.getTarget();
26375 //Roo.log(['leave',dom]);
26376 if (!this.currentEl) {
26381 if (dom != this.currentEl.dom) {
26384 var xy = ev.getXY();
26385 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26388 // only activate leave if mouse cursor is outside... bounding box..
26393 if (this.currentTip) {
26394 this.currentTip.leave();
26396 //Roo.log('clear currentEl');
26397 this.currentEl = false;
26402 'left' : ['r-l', [-2,0], 'right'],
26403 'right' : ['l-r', [2,0], 'left'],
26404 'bottom' : ['t-b', [0,2], 'top'],
26405 'top' : [ 'b-t', [0,-2], 'bottom']
26411 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26416 delay : null, // can be { show : 300 , hide: 500}
26420 hoverState : null, //???
26422 placement : 'bottom',
26426 getAutoCreate : function(){
26433 cls : 'tooltip-arrow'
26436 cls : 'tooltip-inner'
26443 bind : function(el)
26449 enter : function () {
26451 if (this.timeout != null) {
26452 clearTimeout(this.timeout);
26455 this.hoverState = 'in';
26456 //Roo.log("enter - show");
26457 if (!this.delay || !this.delay.show) {
26462 this.timeout = setTimeout(function () {
26463 if (_t.hoverState == 'in') {
26466 }, this.delay.show);
26470 clearTimeout(this.timeout);
26472 this.hoverState = 'out';
26473 if (!this.delay || !this.delay.hide) {
26479 this.timeout = setTimeout(function () {
26480 //Roo.log("leave - timeout");
26482 if (_t.hoverState == 'out') {
26484 Roo.bootstrap.Tooltip.currentEl = false;
26489 show : function (msg)
26492 this.render(document.body);
26495 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26497 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26499 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26501 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26503 var placement = typeof this.placement == 'function' ?
26504 this.placement.call(this, this.el, on_el) :
26507 var autoToken = /\s?auto?\s?/i;
26508 var autoPlace = autoToken.test(placement);
26510 placement = placement.replace(autoToken, '') || 'top';
26514 //this.el.setXY([0,0]);
26516 //this.el.dom.style.display='block';
26518 //this.el.appendTo(on_el);
26520 var p = this.getPosition();
26521 var box = this.el.getBox();
26527 var align = this.alignment[placement];
26529 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26531 if(placement == 'top' || placement == 'bottom'){
26533 placement = 'right';
26536 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26537 placement = 'left';
26540 var scroll = Roo.select('body', true).first().getScroll();
26542 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26546 align = this.alignment[placement];
26549 this.el.alignTo(this.bindEl, align[0],align[1]);
26550 //var arrow = this.el.select('.arrow',true).first();
26551 //arrow.set(align[2],
26553 this.el.addClass(placement);
26555 this.el.addClass('in fade');
26557 this.hoverState = null;
26559 if (this.el.hasClass('fade')) {
26570 //this.el.setXY([0,0]);
26571 this.el.removeClass('in');
26587 * @class Roo.bootstrap.LocationPicker
26588 * @extends Roo.bootstrap.Component
26589 * Bootstrap LocationPicker class
26590 * @cfg {Number} latitude Position when init default 0
26591 * @cfg {Number} longitude Position when init default 0
26592 * @cfg {Number} zoom default 15
26593 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26594 * @cfg {Boolean} mapTypeControl default false
26595 * @cfg {Boolean} disableDoubleClickZoom default false
26596 * @cfg {Boolean} scrollwheel default true
26597 * @cfg {Boolean} streetViewControl default false
26598 * @cfg {Number} radius default 0
26599 * @cfg {String} locationName
26600 * @cfg {Boolean} draggable default true
26601 * @cfg {Boolean} enableAutocomplete default false
26602 * @cfg {Boolean} enableReverseGeocode default true
26603 * @cfg {String} markerTitle
26606 * Create a new LocationPicker
26607 * @param {Object} config The config object
26611 Roo.bootstrap.LocationPicker = function(config){
26613 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26618 * Fires when the picker initialized.
26619 * @param {Roo.bootstrap.LocationPicker} this
26620 * @param {Google Location} location
26624 * @event positionchanged
26625 * Fires when the picker position changed.
26626 * @param {Roo.bootstrap.LocationPicker} this
26627 * @param {Google Location} location
26629 positionchanged : true,
26632 * Fires when the map resize.
26633 * @param {Roo.bootstrap.LocationPicker} this
26638 * Fires when the map show.
26639 * @param {Roo.bootstrap.LocationPicker} this
26644 * Fires when the map hide.
26645 * @param {Roo.bootstrap.LocationPicker} this
26650 * Fires when click the map.
26651 * @param {Roo.bootstrap.LocationPicker} this
26652 * @param {Map event} e
26656 * @event mapRightClick
26657 * Fires when right click the map.
26658 * @param {Roo.bootstrap.LocationPicker} this
26659 * @param {Map event} e
26661 mapRightClick : true,
26663 * @event markerClick
26664 * Fires when click the marker.
26665 * @param {Roo.bootstrap.LocationPicker} this
26666 * @param {Map event} e
26668 markerClick : true,
26670 * @event markerRightClick
26671 * Fires when right click the marker.
26672 * @param {Roo.bootstrap.LocationPicker} this
26673 * @param {Map event} e
26675 markerRightClick : true,
26677 * @event OverlayViewDraw
26678 * Fires when OverlayView Draw
26679 * @param {Roo.bootstrap.LocationPicker} this
26681 OverlayViewDraw : true,
26683 * @event OverlayViewOnAdd
26684 * Fires when OverlayView Draw
26685 * @param {Roo.bootstrap.LocationPicker} this
26687 OverlayViewOnAdd : true,
26689 * @event OverlayViewOnRemove
26690 * Fires when OverlayView Draw
26691 * @param {Roo.bootstrap.LocationPicker} this
26693 OverlayViewOnRemove : true,
26695 * @event OverlayViewShow
26696 * Fires when OverlayView Draw
26697 * @param {Roo.bootstrap.LocationPicker} this
26698 * @param {Pixel} cpx
26700 OverlayViewShow : true,
26702 * @event OverlayViewHide
26703 * Fires when OverlayView Draw
26704 * @param {Roo.bootstrap.LocationPicker} this
26706 OverlayViewHide : true,
26708 * @event loadexception
26709 * Fires when load google lib failed.
26710 * @param {Roo.bootstrap.LocationPicker} this
26712 loadexception : true
26717 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26719 gMapContext: false,
26725 mapTypeControl: false,
26726 disableDoubleClickZoom: false,
26728 streetViewControl: false,
26732 enableAutocomplete: false,
26733 enableReverseGeocode: true,
26736 getAutoCreate: function()
26741 cls: 'roo-location-picker'
26747 initEvents: function(ct, position)
26749 if(!this.el.getWidth() || this.isApplied()){
26753 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26758 initial: function()
26760 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26761 this.fireEvent('loadexception', this);
26765 if(!this.mapTypeId){
26766 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26769 this.gMapContext = this.GMapContext();
26771 this.initOverlayView();
26773 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26777 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26778 _this.setPosition(_this.gMapContext.marker.position);
26781 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26782 _this.fireEvent('mapClick', this, event);
26786 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26787 _this.fireEvent('mapRightClick', this, event);
26791 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26792 _this.fireEvent('markerClick', this, event);
26796 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26797 _this.fireEvent('markerRightClick', this, event);
26801 this.setPosition(this.gMapContext.location);
26803 this.fireEvent('initial', this, this.gMapContext.location);
26806 initOverlayView: function()
26810 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26814 _this.fireEvent('OverlayViewDraw', _this);
26819 _this.fireEvent('OverlayViewOnAdd', _this);
26822 onRemove: function()
26824 _this.fireEvent('OverlayViewOnRemove', _this);
26827 show: function(cpx)
26829 _this.fireEvent('OverlayViewShow', _this, cpx);
26834 _this.fireEvent('OverlayViewHide', _this);
26840 fromLatLngToContainerPixel: function(event)
26842 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26845 isApplied: function()
26847 return this.getGmapContext() == false ? false : true;
26850 getGmapContext: function()
26852 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26855 GMapContext: function()
26857 var position = new google.maps.LatLng(this.latitude, this.longitude);
26859 var _map = new google.maps.Map(this.el.dom, {
26862 mapTypeId: this.mapTypeId,
26863 mapTypeControl: this.mapTypeControl,
26864 disableDoubleClickZoom: this.disableDoubleClickZoom,
26865 scrollwheel: this.scrollwheel,
26866 streetViewControl: this.streetViewControl,
26867 locationName: this.locationName,
26868 draggable: this.draggable,
26869 enableAutocomplete: this.enableAutocomplete,
26870 enableReverseGeocode: this.enableReverseGeocode
26873 var _marker = new google.maps.Marker({
26874 position: position,
26876 title: this.markerTitle,
26877 draggable: this.draggable
26884 location: position,
26885 radius: this.radius,
26886 locationName: this.locationName,
26887 addressComponents: {
26888 formatted_address: null,
26889 addressLine1: null,
26890 addressLine2: null,
26892 streetNumber: null,
26896 stateOrProvince: null
26899 domContainer: this.el.dom,
26900 geodecoder: new google.maps.Geocoder()
26904 drawCircle: function(center, radius, options)
26906 if (this.gMapContext.circle != null) {
26907 this.gMapContext.circle.setMap(null);
26911 options = Roo.apply({}, options, {
26912 strokeColor: "#0000FF",
26913 strokeOpacity: .35,
26915 fillColor: "#0000FF",
26919 options.map = this.gMapContext.map;
26920 options.radius = radius;
26921 options.center = center;
26922 this.gMapContext.circle = new google.maps.Circle(options);
26923 return this.gMapContext.circle;
26929 setPosition: function(location)
26931 this.gMapContext.location = location;
26932 this.gMapContext.marker.setPosition(location);
26933 this.gMapContext.map.panTo(location);
26934 this.drawCircle(location, this.gMapContext.radius, {});
26938 if (this.gMapContext.settings.enableReverseGeocode) {
26939 this.gMapContext.geodecoder.geocode({
26940 latLng: this.gMapContext.location
26941 }, function(results, status) {
26943 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26944 _this.gMapContext.locationName = results[0].formatted_address;
26945 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26947 _this.fireEvent('positionchanged', this, location);
26954 this.fireEvent('positionchanged', this, location);
26959 google.maps.event.trigger(this.gMapContext.map, "resize");
26961 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26963 this.fireEvent('resize', this);
26966 setPositionByLatLng: function(latitude, longitude)
26968 this.setPosition(new google.maps.LatLng(latitude, longitude));
26971 getCurrentPosition: function()
26974 latitude: this.gMapContext.location.lat(),
26975 longitude: this.gMapContext.location.lng()
26979 getAddressName: function()
26981 return this.gMapContext.locationName;
26984 getAddressComponents: function()
26986 return this.gMapContext.addressComponents;
26989 address_component_from_google_geocode: function(address_components)
26993 for (var i = 0; i < address_components.length; i++) {
26994 var component = address_components[i];
26995 if (component.types.indexOf("postal_code") >= 0) {
26996 result.postalCode = component.short_name;
26997 } else if (component.types.indexOf("street_number") >= 0) {
26998 result.streetNumber = component.short_name;
26999 } else if (component.types.indexOf("route") >= 0) {
27000 result.streetName = component.short_name;
27001 } else if (component.types.indexOf("neighborhood") >= 0) {
27002 result.city = component.short_name;
27003 } else if (component.types.indexOf("locality") >= 0) {
27004 result.city = component.short_name;
27005 } else if (component.types.indexOf("sublocality") >= 0) {
27006 result.district = component.short_name;
27007 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27008 result.stateOrProvince = component.short_name;
27009 } else if (component.types.indexOf("country") >= 0) {
27010 result.country = component.short_name;
27014 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27015 result.addressLine2 = "";
27019 setZoomLevel: function(zoom)
27021 this.gMapContext.map.setZoom(zoom);
27034 this.fireEvent('show', this);
27045 this.fireEvent('hide', this);
27050 Roo.apply(Roo.bootstrap.LocationPicker, {
27052 OverlayView : function(map, options)
27054 options = options || {};
27068 * @class Roo.bootstrap.Alert
27069 * @extends Roo.bootstrap.Component
27070 * Bootstrap Alert class
27071 * @cfg {String} title The title of alert
27072 * @cfg {String} html The content of alert
27073 * @cfg {String} weight ( success | info | warning | danger )
27074 * @cfg {String} faicon font-awesomeicon
27077 * Create a new alert
27078 * @param {Object} config The config object
27082 Roo.bootstrap.Alert = function(config){
27083 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27087 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27094 getAutoCreate : function()
27103 cls : 'roo-alert-icon'
27108 cls : 'roo-alert-title',
27113 cls : 'roo-alert-text',
27120 cfg.cn[0].cls += ' fa ' + this.faicon;
27124 cfg.cls += ' alert-' + this.weight;
27130 initEvents: function()
27132 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27135 setTitle : function(str)
27137 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27140 setText : function(str)
27142 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27145 setWeight : function(weight)
27148 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27151 this.weight = weight;
27153 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27156 setIcon : function(icon)
27159 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27162 this.faicon = icon;
27164 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27185 * @class Roo.bootstrap.UploadCropbox
27186 * @extends Roo.bootstrap.Component
27187 * Bootstrap UploadCropbox class
27188 * @cfg {String} emptyText show when image has been loaded
27189 * @cfg {String} rotateNotify show when image too small to rotate
27190 * @cfg {Number} errorTimeout default 3000
27191 * @cfg {Number} minWidth default 300
27192 * @cfg {Number} minHeight default 300
27193 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27194 * @cfg {Boolean} isDocument (true|false) default false
27195 * @cfg {String} url action url
27196 * @cfg {String} paramName default 'imageUpload'
27197 * @cfg {String} method default POST
27198 * @cfg {Boolean} loadMask (true|false) default true
27199 * @cfg {Boolean} loadingText default 'Loading...'
27202 * Create a new UploadCropbox
27203 * @param {Object} config The config object
27206 Roo.bootstrap.UploadCropbox = function(config){
27207 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27211 * @event beforeselectfile
27212 * Fire before select file
27213 * @param {Roo.bootstrap.UploadCropbox} this
27215 "beforeselectfile" : true,
27218 * Fire after initEvent
27219 * @param {Roo.bootstrap.UploadCropbox} this
27224 * Fire after initEvent
27225 * @param {Roo.bootstrap.UploadCropbox} this
27226 * @param {String} data
27231 * Fire when preparing the file data
27232 * @param {Roo.bootstrap.UploadCropbox} this
27233 * @param {Object} file
27238 * Fire when get exception
27239 * @param {Roo.bootstrap.UploadCropbox} this
27240 * @param {XMLHttpRequest} xhr
27242 "exception" : true,
27244 * @event beforeloadcanvas
27245 * Fire before load the canvas
27246 * @param {Roo.bootstrap.UploadCropbox} this
27247 * @param {String} src
27249 "beforeloadcanvas" : true,
27252 * Fire when trash image
27253 * @param {Roo.bootstrap.UploadCropbox} this
27258 * Fire when download the image
27259 * @param {Roo.bootstrap.UploadCropbox} this
27263 * @event footerbuttonclick
27264 * Fire when footerbuttonclick
27265 * @param {Roo.bootstrap.UploadCropbox} this
27266 * @param {String} type
27268 "footerbuttonclick" : true,
27272 * @param {Roo.bootstrap.UploadCropbox} this
27277 * Fire when rotate the image
27278 * @param {Roo.bootstrap.UploadCropbox} this
27279 * @param {String} pos
27284 * Fire when inspect the file
27285 * @param {Roo.bootstrap.UploadCropbox} this
27286 * @param {Object} file
27291 * Fire when xhr upload the file
27292 * @param {Roo.bootstrap.UploadCropbox} this
27293 * @param {Object} data
27298 * Fire when arrange the file data
27299 * @param {Roo.bootstrap.UploadCropbox} this
27300 * @param {Object} formData
27305 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27308 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27310 emptyText : 'Click to upload image',
27311 rotateNotify : 'Image is too small to rotate',
27312 errorTimeout : 3000,
27326 cropType : 'image/jpeg',
27328 canvasLoaded : false,
27329 isDocument : false,
27331 paramName : 'imageUpload',
27333 loadingText : 'Loading...',
27336 getAutoCreate : function()
27340 cls : 'roo-upload-cropbox',
27344 cls : 'roo-upload-cropbox-selector',
27349 cls : 'roo-upload-cropbox-body',
27350 style : 'cursor:pointer',
27354 cls : 'roo-upload-cropbox-preview'
27358 cls : 'roo-upload-cropbox-thumb'
27362 cls : 'roo-upload-cropbox-empty-notify',
27363 html : this.emptyText
27367 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27368 html : this.rotateNotify
27374 cls : 'roo-upload-cropbox-footer',
27377 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27387 onRender : function(ct, position)
27389 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27391 if (this.buttons.length) {
27393 Roo.each(this.buttons, function(bb) {
27395 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27397 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27403 this.maskEl = this.el;
27407 initEvents : function()
27409 this.urlAPI = (window.createObjectURL && window) ||
27410 (window.URL && URL.revokeObjectURL && URL) ||
27411 (window.webkitURL && webkitURL);
27413 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27414 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27416 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27417 this.selectorEl.hide();
27419 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27420 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27422 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27423 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27424 this.thumbEl.hide();
27426 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27427 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27429 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27430 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27431 this.errorEl.hide();
27433 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27434 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27435 this.footerEl.hide();
27437 this.setThumbBoxSize();
27443 this.fireEvent('initial', this);
27450 window.addEventListener("resize", function() { _this.resize(); } );
27452 this.bodyEl.on('click', this.beforeSelectFile, this);
27455 this.bodyEl.on('touchstart', this.onTouchStart, this);
27456 this.bodyEl.on('touchmove', this.onTouchMove, this);
27457 this.bodyEl.on('touchend', this.onTouchEnd, this);
27461 this.bodyEl.on('mousedown', this.onMouseDown, this);
27462 this.bodyEl.on('mousemove', this.onMouseMove, this);
27463 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27464 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27465 Roo.get(document).on('mouseup', this.onMouseUp, this);
27468 this.selectorEl.on('change', this.onFileSelected, this);
27474 this.baseScale = 1;
27476 this.baseRotate = 1;
27477 this.dragable = false;
27478 this.pinching = false;
27481 this.cropData = false;
27482 this.notifyEl.dom.innerHTML = this.emptyText;
27484 this.selectorEl.dom.value = '';
27488 resize : function()
27490 if(this.fireEvent('resize', this) != false){
27491 this.setThumbBoxPosition();
27492 this.setCanvasPosition();
27496 onFooterButtonClick : function(e, el, o, type)
27499 case 'rotate-left' :
27500 this.onRotateLeft(e);
27502 case 'rotate-right' :
27503 this.onRotateRight(e);
27506 this.beforeSelectFile(e);
27521 this.fireEvent('footerbuttonclick', this, type);
27524 beforeSelectFile : function(e)
27526 e.preventDefault();
27528 if(this.fireEvent('beforeselectfile', this) != false){
27529 this.selectorEl.dom.click();
27533 onFileSelected : function(e)
27535 e.preventDefault();
27537 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27541 var file = this.selectorEl.dom.files[0];
27543 if(this.fireEvent('inspect', this, file) != false){
27544 this.prepare(file);
27549 trash : function(e)
27551 this.fireEvent('trash', this);
27554 download : function(e)
27556 this.fireEvent('download', this);
27559 loadCanvas : function(src)
27561 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27565 this.imageEl = document.createElement('img');
27569 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27571 this.imageEl.src = src;
27575 onLoadCanvas : function()
27577 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27578 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27580 this.bodyEl.un('click', this.beforeSelectFile, this);
27582 this.notifyEl.hide();
27583 this.thumbEl.show();
27584 this.footerEl.show();
27586 this.baseRotateLevel();
27588 if(this.isDocument){
27589 this.setThumbBoxSize();
27592 this.setThumbBoxPosition();
27594 this.baseScaleLevel();
27600 this.canvasLoaded = true;
27603 this.maskEl.unmask();
27608 setCanvasPosition : function()
27610 if(!this.canvasEl){
27614 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27615 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27617 this.previewEl.setLeft(pw);
27618 this.previewEl.setTop(ph);
27622 onMouseDown : function(e)
27626 this.dragable = true;
27627 this.pinching = false;
27629 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27630 this.dragable = false;
27634 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27635 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27639 onMouseMove : function(e)
27643 if(!this.canvasLoaded){
27647 if (!this.dragable){
27651 var minX = Math.ceil(this.thumbEl.getLeft(true));
27652 var minY = Math.ceil(this.thumbEl.getTop(true));
27654 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27655 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27657 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27658 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27660 x = x - this.mouseX;
27661 y = y - this.mouseY;
27663 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27664 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27666 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27667 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27669 this.previewEl.setLeft(bgX);
27670 this.previewEl.setTop(bgY);
27672 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27673 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27676 onMouseUp : function(e)
27680 this.dragable = false;
27683 onMouseWheel : function(e)
27687 this.startScale = this.scale;
27689 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27691 if(!this.zoomable()){
27692 this.scale = this.startScale;
27701 zoomable : function()
27703 var minScale = this.thumbEl.getWidth() / this.minWidth;
27705 if(this.minWidth < this.minHeight){
27706 minScale = this.thumbEl.getHeight() / this.minHeight;
27709 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27710 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27714 (this.rotate == 0 || this.rotate == 180) &&
27716 width > this.imageEl.OriginWidth ||
27717 height > this.imageEl.OriginHeight ||
27718 (width < this.minWidth && height < this.minHeight)
27726 (this.rotate == 90 || this.rotate == 270) &&
27728 width > this.imageEl.OriginWidth ||
27729 height > this.imageEl.OriginHeight ||
27730 (width < this.minHeight && height < this.minWidth)
27737 !this.isDocument &&
27738 (this.rotate == 0 || this.rotate == 180) &&
27740 width < this.minWidth ||
27741 width > this.imageEl.OriginWidth ||
27742 height < this.minHeight ||
27743 height > this.imageEl.OriginHeight
27750 !this.isDocument &&
27751 (this.rotate == 90 || this.rotate == 270) &&
27753 width < this.minHeight ||
27754 width > this.imageEl.OriginWidth ||
27755 height < this.minWidth ||
27756 height > this.imageEl.OriginHeight
27766 onRotateLeft : function(e)
27768 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27770 var minScale = this.thumbEl.getWidth() / this.minWidth;
27772 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27773 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27775 this.startScale = this.scale;
27777 while (this.getScaleLevel() < minScale){
27779 this.scale = this.scale + 1;
27781 if(!this.zoomable()){
27786 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27787 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27792 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27799 this.scale = this.startScale;
27801 this.onRotateFail();
27806 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27808 if(this.isDocument){
27809 this.setThumbBoxSize();
27810 this.setThumbBoxPosition();
27811 this.setCanvasPosition();
27816 this.fireEvent('rotate', this, 'left');
27820 onRotateRight : function(e)
27822 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27824 var minScale = this.thumbEl.getWidth() / this.minWidth;
27826 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27827 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27829 this.startScale = this.scale;
27831 while (this.getScaleLevel() < minScale){
27833 this.scale = this.scale + 1;
27835 if(!this.zoomable()){
27840 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27841 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27846 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27853 this.scale = this.startScale;
27855 this.onRotateFail();
27860 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27862 if(this.isDocument){
27863 this.setThumbBoxSize();
27864 this.setThumbBoxPosition();
27865 this.setCanvasPosition();
27870 this.fireEvent('rotate', this, 'right');
27873 onRotateFail : function()
27875 this.errorEl.show(true);
27879 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27884 this.previewEl.dom.innerHTML = '';
27886 var canvasEl = document.createElement("canvas");
27888 var contextEl = canvasEl.getContext("2d");
27890 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27891 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27892 var center = this.imageEl.OriginWidth / 2;
27894 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27895 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27896 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27897 center = this.imageEl.OriginHeight / 2;
27900 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27902 contextEl.translate(center, center);
27903 contextEl.rotate(this.rotate * Math.PI / 180);
27905 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27907 this.canvasEl = document.createElement("canvas");
27909 this.contextEl = this.canvasEl.getContext("2d");
27911 switch (this.rotate) {
27914 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27915 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27917 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27922 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27923 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27925 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27926 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);
27930 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27935 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27936 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27938 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27939 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);
27943 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);
27948 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27949 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27951 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27952 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27956 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);
27963 this.previewEl.appendChild(this.canvasEl);
27965 this.setCanvasPosition();
27970 if(!this.canvasLoaded){
27974 var imageCanvas = document.createElement("canvas");
27976 var imageContext = imageCanvas.getContext("2d");
27978 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27979 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27981 var center = imageCanvas.width / 2;
27983 imageContext.translate(center, center);
27985 imageContext.rotate(this.rotate * Math.PI / 180);
27987 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27989 var canvas = document.createElement("canvas");
27991 var context = canvas.getContext("2d");
27993 canvas.width = this.minWidth;
27994 canvas.height = this.minHeight;
27996 switch (this.rotate) {
27999 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28000 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28002 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28003 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28005 var targetWidth = this.minWidth - 2 * x;
28006 var targetHeight = this.minHeight - 2 * y;
28010 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28011 scale = targetWidth / width;
28014 if(x > 0 && y == 0){
28015 scale = targetHeight / height;
28018 if(x > 0 && y > 0){
28019 scale = targetWidth / width;
28021 if(width < height){
28022 scale = targetHeight / height;
28026 context.scale(scale, scale);
28028 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28029 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28031 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28032 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28034 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28039 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28040 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28042 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28043 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28045 var targetWidth = this.minWidth - 2 * x;
28046 var targetHeight = this.minHeight - 2 * y;
28050 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28051 scale = targetWidth / width;
28054 if(x > 0 && y == 0){
28055 scale = targetHeight / height;
28058 if(x > 0 && y > 0){
28059 scale = targetWidth / width;
28061 if(width < height){
28062 scale = targetHeight / height;
28066 context.scale(scale, scale);
28068 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28069 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28071 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28072 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28074 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28076 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28081 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28082 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28084 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28085 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28087 var targetWidth = this.minWidth - 2 * x;
28088 var targetHeight = this.minHeight - 2 * y;
28092 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28093 scale = targetWidth / width;
28096 if(x > 0 && y == 0){
28097 scale = targetHeight / height;
28100 if(x > 0 && y > 0){
28101 scale = targetWidth / width;
28103 if(width < height){
28104 scale = targetHeight / height;
28108 context.scale(scale, scale);
28110 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28111 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28113 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28114 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28116 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28117 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28119 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28124 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28125 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28127 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28128 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28130 var targetWidth = this.minWidth - 2 * x;
28131 var targetHeight = this.minHeight - 2 * y;
28135 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28136 scale = targetWidth / width;
28139 if(x > 0 && y == 0){
28140 scale = targetHeight / height;
28143 if(x > 0 && y > 0){
28144 scale = targetWidth / width;
28146 if(width < height){
28147 scale = targetHeight / height;
28151 context.scale(scale, scale);
28153 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28154 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28156 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28157 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28159 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28161 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28168 this.cropData = canvas.toDataURL(this.cropType);
28170 if(this.fireEvent('crop', this, this.cropData) !== false){
28171 this.process(this.file, this.cropData);
28178 setThumbBoxSize : function()
28182 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28183 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28184 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28186 this.minWidth = width;
28187 this.minHeight = height;
28189 if(this.rotate == 90 || this.rotate == 270){
28190 this.minWidth = height;
28191 this.minHeight = width;
28196 width = Math.ceil(this.minWidth * height / this.minHeight);
28198 if(this.minWidth > this.minHeight){
28200 height = Math.ceil(this.minHeight * width / this.minWidth);
28203 this.thumbEl.setStyle({
28204 width : width + 'px',
28205 height : height + 'px'
28212 setThumbBoxPosition : function()
28214 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28215 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28217 this.thumbEl.setLeft(x);
28218 this.thumbEl.setTop(y);
28222 baseRotateLevel : function()
28224 this.baseRotate = 1;
28227 typeof(this.exif) != 'undefined' &&
28228 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28229 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28231 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28234 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28238 baseScaleLevel : function()
28242 if(this.isDocument){
28244 if(this.baseRotate == 6 || this.baseRotate == 8){
28246 height = this.thumbEl.getHeight();
28247 this.baseScale = height / this.imageEl.OriginWidth;
28249 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28250 width = this.thumbEl.getWidth();
28251 this.baseScale = width / this.imageEl.OriginHeight;
28257 height = this.thumbEl.getHeight();
28258 this.baseScale = height / this.imageEl.OriginHeight;
28260 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28261 width = this.thumbEl.getWidth();
28262 this.baseScale = width / this.imageEl.OriginWidth;
28268 if(this.baseRotate == 6 || this.baseRotate == 8){
28270 width = this.thumbEl.getHeight();
28271 this.baseScale = width / this.imageEl.OriginHeight;
28273 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28274 height = this.thumbEl.getWidth();
28275 this.baseScale = height / this.imageEl.OriginHeight;
28278 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28279 height = this.thumbEl.getWidth();
28280 this.baseScale = height / this.imageEl.OriginHeight;
28282 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28283 width = this.thumbEl.getHeight();
28284 this.baseScale = width / this.imageEl.OriginWidth;
28291 width = this.thumbEl.getWidth();
28292 this.baseScale = width / this.imageEl.OriginWidth;
28294 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28295 height = this.thumbEl.getHeight();
28296 this.baseScale = height / this.imageEl.OriginHeight;
28299 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28301 height = this.thumbEl.getHeight();
28302 this.baseScale = height / this.imageEl.OriginHeight;
28304 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28305 width = this.thumbEl.getWidth();
28306 this.baseScale = width / this.imageEl.OriginWidth;
28314 getScaleLevel : function()
28316 return this.baseScale * Math.pow(1.1, this.scale);
28319 onTouchStart : function(e)
28321 if(!this.canvasLoaded){
28322 this.beforeSelectFile(e);
28326 var touches = e.browserEvent.touches;
28332 if(touches.length == 1){
28333 this.onMouseDown(e);
28337 if(touches.length != 2){
28343 for(var i = 0, finger; finger = touches[i]; i++){
28344 coords.push(finger.pageX, finger.pageY);
28347 var x = Math.pow(coords[0] - coords[2], 2);
28348 var y = Math.pow(coords[1] - coords[3], 2);
28350 this.startDistance = Math.sqrt(x + y);
28352 this.startScale = this.scale;
28354 this.pinching = true;
28355 this.dragable = false;
28359 onTouchMove : function(e)
28361 if(!this.pinching && !this.dragable){
28365 var touches = e.browserEvent.touches;
28372 this.onMouseMove(e);
28378 for(var i = 0, finger; finger = touches[i]; i++){
28379 coords.push(finger.pageX, finger.pageY);
28382 var x = Math.pow(coords[0] - coords[2], 2);
28383 var y = Math.pow(coords[1] - coords[3], 2);
28385 this.endDistance = Math.sqrt(x + y);
28387 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28389 if(!this.zoomable()){
28390 this.scale = this.startScale;
28398 onTouchEnd : function(e)
28400 this.pinching = false;
28401 this.dragable = false;
28405 process : function(file, crop)
28408 this.maskEl.mask(this.loadingText);
28411 this.xhr = new XMLHttpRequest();
28413 file.xhr = this.xhr;
28415 this.xhr.open(this.method, this.url, true);
28418 "Accept": "application/json",
28419 "Cache-Control": "no-cache",
28420 "X-Requested-With": "XMLHttpRequest"
28423 for (var headerName in headers) {
28424 var headerValue = headers[headerName];
28426 this.xhr.setRequestHeader(headerName, headerValue);
28432 this.xhr.onload = function()
28434 _this.xhrOnLoad(_this.xhr);
28437 this.xhr.onerror = function()
28439 _this.xhrOnError(_this.xhr);
28442 var formData = new FormData();
28444 formData.append('returnHTML', 'NO');
28447 formData.append('crop', crop);
28450 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28451 formData.append(this.paramName, file, file.name);
28454 if(typeof(file.filename) != 'undefined'){
28455 formData.append('filename', file.filename);
28458 if(typeof(file.mimetype) != 'undefined'){
28459 formData.append('mimetype', file.mimetype);
28462 if(this.fireEvent('arrange', this, formData) != false){
28463 this.xhr.send(formData);
28467 xhrOnLoad : function(xhr)
28470 this.maskEl.unmask();
28473 if (xhr.readyState !== 4) {
28474 this.fireEvent('exception', this, xhr);
28478 var response = Roo.decode(xhr.responseText);
28480 if(!response.success){
28481 this.fireEvent('exception', this, xhr);
28485 var response = Roo.decode(xhr.responseText);
28487 this.fireEvent('upload', this, response);
28491 xhrOnError : function()
28494 this.maskEl.unmask();
28497 Roo.log('xhr on error');
28499 var response = Roo.decode(xhr.responseText);
28505 prepare : function(file)
28508 this.maskEl.mask(this.loadingText);
28514 if(typeof(file) === 'string'){
28515 this.loadCanvas(file);
28519 if(!file || !this.urlAPI){
28524 this.cropType = file.type;
28528 if(this.fireEvent('prepare', this, this.file) != false){
28530 var reader = new FileReader();
28532 reader.onload = function (e) {
28533 if (e.target.error) {
28534 Roo.log(e.target.error);
28538 var buffer = e.target.result,
28539 dataView = new DataView(buffer),
28541 maxOffset = dataView.byteLength - 4,
28545 if (dataView.getUint16(0) === 0xffd8) {
28546 while (offset < maxOffset) {
28547 markerBytes = dataView.getUint16(offset);
28549 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28550 markerLength = dataView.getUint16(offset + 2) + 2;
28551 if (offset + markerLength > dataView.byteLength) {
28552 Roo.log('Invalid meta data: Invalid segment size.');
28556 if(markerBytes == 0xffe1){
28557 _this.parseExifData(
28564 offset += markerLength;
28574 var url = _this.urlAPI.createObjectURL(_this.file);
28576 _this.loadCanvas(url);
28581 reader.readAsArrayBuffer(this.file);
28587 parseExifData : function(dataView, offset, length)
28589 var tiffOffset = offset + 10,
28593 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28594 // No Exif data, might be XMP data instead
28598 // Check for the ASCII code for "Exif" (0x45786966):
28599 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28600 // No Exif data, might be XMP data instead
28603 if (tiffOffset + 8 > dataView.byteLength) {
28604 Roo.log('Invalid Exif data: Invalid segment size.');
28607 // Check for the two null bytes:
28608 if (dataView.getUint16(offset + 8) !== 0x0000) {
28609 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28612 // Check the byte alignment:
28613 switch (dataView.getUint16(tiffOffset)) {
28615 littleEndian = true;
28618 littleEndian = false;
28621 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28624 // Check for the TIFF tag marker (0x002A):
28625 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28626 Roo.log('Invalid Exif data: Missing TIFF marker.');
28629 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28630 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28632 this.parseExifTags(
28635 tiffOffset + dirOffset,
28640 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28645 if (dirOffset + 6 > dataView.byteLength) {
28646 Roo.log('Invalid Exif data: Invalid directory offset.');
28649 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28650 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28651 if (dirEndOffset + 4 > dataView.byteLength) {
28652 Roo.log('Invalid Exif data: Invalid directory size.');
28655 for (i = 0; i < tagsNumber; i += 1) {
28659 dirOffset + 2 + 12 * i, // tag offset
28663 // Return the offset to the next directory:
28664 return dataView.getUint32(dirEndOffset, littleEndian);
28667 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28669 var tag = dataView.getUint16(offset, littleEndian);
28671 this.exif[tag] = this.getExifValue(
28675 dataView.getUint16(offset + 2, littleEndian), // tag type
28676 dataView.getUint32(offset + 4, littleEndian), // tag length
28681 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28683 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28692 Roo.log('Invalid Exif data: Invalid tag type.');
28696 tagSize = tagType.size * length;
28697 // Determine if the value is contained in the dataOffset bytes,
28698 // or if the value at the dataOffset is a pointer to the actual data:
28699 dataOffset = tagSize > 4 ?
28700 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28701 if (dataOffset + tagSize > dataView.byteLength) {
28702 Roo.log('Invalid Exif data: Invalid data offset.');
28705 if (length === 1) {
28706 return tagType.getValue(dataView, dataOffset, littleEndian);
28709 for (i = 0; i < length; i += 1) {
28710 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28713 if (tagType.ascii) {
28715 // Concatenate the chars:
28716 for (i = 0; i < values.length; i += 1) {
28718 // Ignore the terminating NULL byte(s):
28719 if (c === '\u0000') {
28731 Roo.apply(Roo.bootstrap.UploadCropbox, {
28733 'Orientation': 0x0112
28737 1: 0, //'top-left',
28739 3: 180, //'bottom-right',
28740 // 4: 'bottom-left',
28742 6: 90, //'right-top',
28743 // 7: 'right-bottom',
28744 8: 270 //'left-bottom'
28748 // byte, 8-bit unsigned int:
28750 getValue: function (dataView, dataOffset) {
28751 return dataView.getUint8(dataOffset);
28755 // ascii, 8-bit byte:
28757 getValue: function (dataView, dataOffset) {
28758 return String.fromCharCode(dataView.getUint8(dataOffset));
28763 // short, 16 bit int:
28765 getValue: function (dataView, dataOffset, littleEndian) {
28766 return dataView.getUint16(dataOffset, littleEndian);
28770 // long, 32 bit int:
28772 getValue: function (dataView, dataOffset, littleEndian) {
28773 return dataView.getUint32(dataOffset, littleEndian);
28777 // rational = two long values, first is numerator, second is denominator:
28779 getValue: function (dataView, dataOffset, littleEndian) {
28780 return dataView.getUint32(dataOffset, littleEndian) /
28781 dataView.getUint32(dataOffset + 4, littleEndian);
28785 // slong, 32 bit signed int:
28787 getValue: function (dataView, dataOffset, littleEndian) {
28788 return dataView.getInt32(dataOffset, littleEndian);
28792 // srational, two slongs, first is numerator, second is denominator:
28794 getValue: function (dataView, dataOffset, littleEndian) {
28795 return dataView.getInt32(dataOffset, littleEndian) /
28796 dataView.getInt32(dataOffset + 4, littleEndian);
28806 cls : 'btn-group roo-upload-cropbox-rotate-left',
28807 action : 'rotate-left',
28811 cls : 'btn btn-default',
28812 html : '<i class="fa fa-undo"></i>'
28818 cls : 'btn-group roo-upload-cropbox-picture',
28819 action : 'picture',
28823 cls : 'btn btn-default',
28824 html : '<i class="fa fa-picture-o"></i>'
28830 cls : 'btn-group roo-upload-cropbox-rotate-right',
28831 action : 'rotate-right',
28835 cls : 'btn btn-default',
28836 html : '<i class="fa fa-repeat"></i>'
28844 cls : 'btn-group roo-upload-cropbox-rotate-left',
28845 action : 'rotate-left',
28849 cls : 'btn btn-default',
28850 html : '<i class="fa fa-undo"></i>'
28856 cls : 'btn-group roo-upload-cropbox-download',
28857 action : 'download',
28861 cls : 'btn btn-default',
28862 html : '<i class="fa fa-download"></i>'
28868 cls : 'btn-group roo-upload-cropbox-crop',
28873 cls : 'btn btn-default',
28874 html : '<i class="fa fa-crop"></i>'
28880 cls : 'btn-group roo-upload-cropbox-trash',
28885 cls : 'btn btn-default',
28886 html : '<i class="fa fa-trash"></i>'
28892 cls : 'btn-group roo-upload-cropbox-rotate-right',
28893 action : 'rotate-right',
28897 cls : 'btn btn-default',
28898 html : '<i class="fa fa-repeat"></i>'
28906 cls : 'btn-group roo-upload-cropbox-rotate-left',
28907 action : 'rotate-left',
28911 cls : 'btn btn-default',
28912 html : '<i class="fa fa-undo"></i>'
28918 cls : 'btn-group roo-upload-cropbox-rotate-right',
28919 action : 'rotate-right',
28923 cls : 'btn btn-default',
28924 html : '<i class="fa fa-repeat"></i>'
28937 * @class Roo.bootstrap.DocumentManager
28938 * @extends Roo.bootstrap.Component
28939 * Bootstrap DocumentManager class
28940 * @cfg {String} paramName default 'imageUpload'
28941 * @cfg {String} toolTipName default 'filename'
28942 * @cfg {String} method default POST
28943 * @cfg {String} url action url
28944 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28945 * @cfg {Boolean} multiple multiple upload default true
28946 * @cfg {Number} thumbSize default 300
28947 * @cfg {String} fieldLabel
28948 * @cfg {Number} labelWidth default 4
28949 * @cfg {String} labelAlign (left|top) default left
28950 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28951 * @cfg {Number} labellg set the width of label (1-12)
28952 * @cfg {Number} labelmd set the width of label (1-12)
28953 * @cfg {Number} labelsm set the width of label (1-12)
28954 * @cfg {Number} labelxs set the width of label (1-12)
28957 * Create a new DocumentManager
28958 * @param {Object} config The config object
28961 Roo.bootstrap.DocumentManager = function(config){
28962 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28965 this.delegates = [];
28970 * Fire when initial the DocumentManager
28971 * @param {Roo.bootstrap.DocumentManager} this
28976 * inspect selected file
28977 * @param {Roo.bootstrap.DocumentManager} this
28978 * @param {File} file
28983 * Fire when xhr load exception
28984 * @param {Roo.bootstrap.DocumentManager} this
28985 * @param {XMLHttpRequest} xhr
28987 "exception" : true,
28989 * @event afterupload
28990 * Fire when xhr load exception
28991 * @param {Roo.bootstrap.DocumentManager} this
28992 * @param {XMLHttpRequest} xhr
28994 "afterupload" : true,
28997 * prepare the form data
28998 * @param {Roo.bootstrap.DocumentManager} this
28999 * @param {Object} formData
29004 * Fire when remove the file
29005 * @param {Roo.bootstrap.DocumentManager} this
29006 * @param {Object} file
29011 * Fire after refresh the file
29012 * @param {Roo.bootstrap.DocumentManager} this
29017 * Fire after click the image
29018 * @param {Roo.bootstrap.DocumentManager} this
29019 * @param {Object} file
29024 * Fire when upload a image and editable set to true
29025 * @param {Roo.bootstrap.DocumentManager} this
29026 * @param {Object} file
29030 * @event beforeselectfile
29031 * Fire before select file
29032 * @param {Roo.bootstrap.DocumentManager} this
29034 "beforeselectfile" : true,
29037 * Fire before process file
29038 * @param {Roo.bootstrap.DocumentManager} this
29039 * @param {Object} file
29043 * @event previewrendered
29044 * Fire when preview rendered
29045 * @param {Roo.bootstrap.DocumentManager} this
29046 * @param {Object} file
29048 "previewrendered" : true,
29051 "previewResize" : true
29056 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29065 paramName : 'imageUpload',
29066 toolTipName : 'filename',
29069 labelAlign : 'left',
29079 getAutoCreate : function()
29081 var managerWidget = {
29083 cls : 'roo-document-manager',
29087 cls : 'roo-document-manager-selector',
29092 cls : 'roo-document-manager-uploader',
29096 cls : 'roo-document-manager-upload-btn',
29097 html : '<i class="fa fa-plus"></i>'
29108 cls : 'column col-md-12',
29113 if(this.fieldLabel.length){
29118 cls : 'column col-md-12',
29119 html : this.fieldLabel
29123 cls : 'column col-md-12',
29128 if(this.labelAlign == 'left'){
29133 html : this.fieldLabel
29142 if(this.labelWidth > 12){
29143 content[0].style = "width: " + this.labelWidth + 'px';
29146 if(this.labelWidth < 13 && this.labelmd == 0){
29147 this.labelmd = this.labelWidth;
29150 if(this.labellg > 0){
29151 content[0].cls += ' col-lg-' + this.labellg;
29152 content[1].cls += ' col-lg-' + (12 - this.labellg);
29155 if(this.labelmd > 0){
29156 content[0].cls += ' col-md-' + this.labelmd;
29157 content[1].cls += ' col-md-' + (12 - this.labelmd);
29160 if(this.labelsm > 0){
29161 content[0].cls += ' col-sm-' + this.labelsm;
29162 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29165 if(this.labelxs > 0){
29166 content[0].cls += ' col-xs-' + this.labelxs;
29167 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29175 cls : 'row clearfix',
29183 initEvents : function()
29185 this.managerEl = this.el.select('.roo-document-manager', true).first();
29186 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29188 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29189 this.selectorEl.hide();
29192 this.selectorEl.attr('multiple', 'multiple');
29195 this.selectorEl.on('change', this.onFileSelected, this);
29197 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29198 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29200 this.uploader.on('click', this.onUploaderClick, this);
29202 this.renderProgressDialog();
29206 window.addEventListener("resize", function() { _this.refresh(); } );
29208 this.fireEvent('initial', this);
29211 renderProgressDialog : function()
29215 this.progressDialog = new Roo.bootstrap.Modal({
29216 cls : 'roo-document-manager-progress-dialog',
29217 allow_close : false,
29228 btnclick : function() {
29229 _this.uploadCancel();
29235 this.progressDialog.render(Roo.get(document.body));
29237 this.progress = new Roo.bootstrap.Progress({
29238 cls : 'roo-document-manager-progress',
29243 this.progress.render(this.progressDialog.getChildContainer());
29245 this.progressBar = new Roo.bootstrap.ProgressBar({
29246 cls : 'roo-document-manager-progress-bar',
29249 aria_valuemax : 12,
29253 this.progressBar.render(this.progress.getChildContainer());
29256 onUploaderClick : function(e)
29258 e.preventDefault();
29260 if(this.fireEvent('beforeselectfile', this) != false){
29261 this.selectorEl.dom.click();
29266 onFileSelected : function(e)
29268 e.preventDefault();
29270 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29274 Roo.each(this.selectorEl.dom.files, function(file){
29275 if(this.fireEvent('inspect', this, file) != false){
29276 this.files.push(file);
29286 this.selectorEl.dom.value = '';
29288 if(!this.files || !this.files.length){
29292 if(this.boxes > 0 && this.files.length > this.boxes){
29293 this.files = this.files.slice(0, this.boxes);
29296 this.uploader.show();
29298 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29299 this.uploader.hide();
29308 Roo.each(this.files, function(file){
29310 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29311 var f = this.renderPreview(file);
29316 if(file.type.indexOf('image') != -1){
29317 this.delegates.push(
29319 _this.process(file);
29320 }).createDelegate(this)
29328 _this.process(file);
29329 }).createDelegate(this)
29334 this.files = files;
29336 this.delegates = this.delegates.concat(docs);
29338 if(!this.delegates.length){
29343 this.progressBar.aria_valuemax = this.delegates.length;
29350 arrange : function()
29352 if(!this.delegates.length){
29353 this.progressDialog.hide();
29358 var delegate = this.delegates.shift();
29360 this.progressDialog.show();
29362 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29364 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29369 refresh : function()
29371 this.uploader.show();
29373 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29374 this.uploader.hide();
29377 Roo.isTouch ? this.closable(false) : this.closable(true);
29379 this.fireEvent('refresh', this);
29382 onRemove : function(e, el, o)
29384 e.preventDefault();
29386 this.fireEvent('remove', this, o);
29390 remove : function(o)
29394 Roo.each(this.files, function(file){
29395 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29404 this.files = files;
29411 Roo.each(this.files, function(file){
29416 file.target.remove();
29425 onClick : function(e, el, o)
29427 e.preventDefault();
29429 this.fireEvent('click', this, o);
29433 closable : function(closable)
29435 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29437 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29449 xhrOnLoad : function(xhr)
29451 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29455 if (xhr.readyState !== 4) {
29457 this.fireEvent('exception', this, xhr);
29461 var response = Roo.decode(xhr.responseText);
29463 if(!response.success){
29465 this.fireEvent('exception', this, xhr);
29469 var file = this.renderPreview(response.data);
29471 this.files.push(file);
29475 this.fireEvent('afterupload', this, xhr);
29479 xhrOnError : function(xhr)
29481 Roo.log('xhr on error');
29483 var response = Roo.decode(xhr.responseText);
29490 process : function(file)
29492 if(this.fireEvent('process', this, file) !== false){
29493 if(this.editable && file.type.indexOf('image') != -1){
29494 this.fireEvent('edit', this, file);
29498 this.uploadStart(file, false);
29505 uploadStart : function(file, crop)
29507 this.xhr = new XMLHttpRequest();
29509 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29514 file.xhr = this.xhr;
29516 this.managerEl.createChild({
29518 cls : 'roo-document-manager-loading',
29522 tooltip : file.name,
29523 cls : 'roo-document-manager-thumb',
29524 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29530 this.xhr.open(this.method, this.url, true);
29533 "Accept": "application/json",
29534 "Cache-Control": "no-cache",
29535 "X-Requested-With": "XMLHttpRequest"
29538 for (var headerName in headers) {
29539 var headerValue = headers[headerName];
29541 this.xhr.setRequestHeader(headerName, headerValue);
29547 this.xhr.onload = function()
29549 _this.xhrOnLoad(_this.xhr);
29552 this.xhr.onerror = function()
29554 _this.xhrOnError(_this.xhr);
29557 var formData = new FormData();
29559 formData.append('returnHTML', 'NO');
29562 formData.append('crop', crop);
29565 formData.append(this.paramName, file, file.name);
29572 if(this.fireEvent('prepare', this, formData, options) != false){
29574 if(options.manually){
29578 this.xhr.send(formData);
29582 this.uploadCancel();
29585 uploadCancel : function()
29591 this.delegates = [];
29593 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29600 renderPreview : function(file)
29602 if(typeof(file.target) != 'undefined' && file.target){
29606 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29608 var previewEl = this.managerEl.createChild({
29610 cls : 'roo-document-manager-preview',
29614 tooltip : file[this.toolTipName],
29615 cls : 'roo-document-manager-thumb',
29616 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29621 html : '<i class="fa fa-times-circle"></i>'
29626 var close = previewEl.select('button.close', true).first();
29628 close.on('click', this.onRemove, this, file);
29630 file.target = previewEl;
29632 var image = previewEl.select('img', true).first();
29636 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29638 image.on('click', this.onClick, this, file);
29640 this.fireEvent('previewrendered', this, file);
29646 onPreviewLoad : function(file, image)
29648 if(typeof(file.target) == 'undefined' || !file.target){
29652 var width = image.dom.naturalWidth || image.dom.width;
29653 var height = image.dom.naturalHeight || image.dom.height;
29655 if(!this.previewResize) {
29659 if(width > height){
29660 file.target.addClass('wide');
29664 file.target.addClass('tall');
29669 uploadFromSource : function(file, crop)
29671 this.xhr = new XMLHttpRequest();
29673 this.managerEl.createChild({
29675 cls : 'roo-document-manager-loading',
29679 tooltip : file.name,
29680 cls : 'roo-document-manager-thumb',
29681 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29687 this.xhr.open(this.method, this.url, true);
29690 "Accept": "application/json",
29691 "Cache-Control": "no-cache",
29692 "X-Requested-With": "XMLHttpRequest"
29695 for (var headerName in headers) {
29696 var headerValue = headers[headerName];
29698 this.xhr.setRequestHeader(headerName, headerValue);
29704 this.xhr.onload = function()
29706 _this.xhrOnLoad(_this.xhr);
29709 this.xhr.onerror = function()
29711 _this.xhrOnError(_this.xhr);
29714 var formData = new FormData();
29716 formData.append('returnHTML', 'NO');
29718 formData.append('crop', crop);
29720 if(typeof(file.filename) != 'undefined'){
29721 formData.append('filename', file.filename);
29724 if(typeof(file.mimetype) != 'undefined'){
29725 formData.append('mimetype', file.mimetype);
29730 if(this.fireEvent('prepare', this, formData) != false){
29731 this.xhr.send(formData);
29741 * @class Roo.bootstrap.DocumentViewer
29742 * @extends Roo.bootstrap.Component
29743 * Bootstrap DocumentViewer class
29744 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29745 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29748 * Create a new DocumentViewer
29749 * @param {Object} config The config object
29752 Roo.bootstrap.DocumentViewer = function(config){
29753 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29758 * Fire after initEvent
29759 * @param {Roo.bootstrap.DocumentViewer} this
29765 * @param {Roo.bootstrap.DocumentViewer} this
29770 * Fire after download button
29771 * @param {Roo.bootstrap.DocumentViewer} this
29776 * Fire after trash button
29777 * @param {Roo.bootstrap.DocumentViewer} this
29784 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29786 showDownload : true,
29790 getAutoCreate : function()
29794 cls : 'roo-document-viewer',
29798 cls : 'roo-document-viewer-body',
29802 cls : 'roo-document-viewer-thumb',
29806 cls : 'roo-document-viewer-image'
29814 cls : 'roo-document-viewer-footer',
29817 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29821 cls : 'btn-group roo-document-viewer-download',
29825 cls : 'btn btn-default',
29826 html : '<i class="fa fa-download"></i>'
29832 cls : 'btn-group roo-document-viewer-trash',
29836 cls : 'btn btn-default',
29837 html : '<i class="fa fa-trash"></i>'
29850 initEvents : function()
29852 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29853 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29855 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29856 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29858 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29859 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29861 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29862 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29864 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29865 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29867 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29868 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29870 this.bodyEl.on('click', this.onClick, this);
29871 this.downloadBtn.on('click', this.onDownload, this);
29872 this.trashBtn.on('click', this.onTrash, this);
29874 this.downloadBtn.hide();
29875 this.trashBtn.hide();
29877 if(this.showDownload){
29878 this.downloadBtn.show();
29881 if(this.showTrash){
29882 this.trashBtn.show();
29885 if(!this.showDownload && !this.showTrash) {
29886 this.footerEl.hide();
29891 initial : function()
29893 this.fireEvent('initial', this);
29897 onClick : function(e)
29899 e.preventDefault();
29901 this.fireEvent('click', this);
29904 onDownload : function(e)
29906 e.preventDefault();
29908 this.fireEvent('download', this);
29911 onTrash : function(e)
29913 e.preventDefault();
29915 this.fireEvent('trash', this);
29927 * @class Roo.bootstrap.NavProgressBar
29928 * @extends Roo.bootstrap.Component
29929 * Bootstrap NavProgressBar class
29932 * Create a new nav progress bar
29933 * @param {Object} config The config object
29936 Roo.bootstrap.NavProgressBar = function(config){
29937 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29939 this.bullets = this.bullets || [];
29941 // Roo.bootstrap.NavProgressBar.register(this);
29945 * Fires when the active item changes
29946 * @param {Roo.bootstrap.NavProgressBar} this
29947 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29948 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29955 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29960 getAutoCreate : function()
29962 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29966 cls : 'roo-navigation-bar-group',
29970 cls : 'roo-navigation-top-bar'
29974 cls : 'roo-navigation-bullets-bar',
29978 cls : 'roo-navigation-bar'
29985 cls : 'roo-navigation-bottom-bar'
29995 initEvents: function()
30000 onRender : function(ct, position)
30002 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30004 if(this.bullets.length){
30005 Roo.each(this.bullets, function(b){
30014 addItem : function(cfg)
30016 var item = new Roo.bootstrap.NavProgressItem(cfg);
30018 item.parentId = this.id;
30019 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30022 var top = new Roo.bootstrap.Element({
30024 cls : 'roo-navigation-bar-text'
30027 var bottom = new Roo.bootstrap.Element({
30029 cls : 'roo-navigation-bar-text'
30032 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30033 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30035 var topText = new Roo.bootstrap.Element({
30037 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30040 var bottomText = new Roo.bootstrap.Element({
30042 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30045 topText.onRender(top.el, null);
30046 bottomText.onRender(bottom.el, null);
30049 item.bottomEl = bottom;
30052 this.barItems.push(item);
30057 getActive : function()
30059 var active = false;
30061 Roo.each(this.barItems, function(v){
30063 if (!v.isActive()) {
30075 setActiveItem : function(item)
30079 Roo.each(this.barItems, function(v){
30080 if (v.rid == item.rid) {
30084 if (v.isActive()) {
30085 v.setActive(false);
30090 item.setActive(true);
30092 this.fireEvent('changed', this, item, prev);
30095 getBarItem: function(rid)
30099 Roo.each(this.barItems, function(e) {
30100 if (e.rid != rid) {
30111 indexOfItem : function(item)
30115 Roo.each(this.barItems, function(v, i){
30117 if (v.rid != item.rid) {
30128 setActiveNext : function()
30130 var i = this.indexOfItem(this.getActive());
30132 if (i > this.barItems.length) {
30136 this.setActiveItem(this.barItems[i+1]);
30139 setActivePrev : function()
30141 var i = this.indexOfItem(this.getActive());
30147 this.setActiveItem(this.barItems[i-1]);
30150 format : function()
30152 if(!this.barItems.length){
30156 var width = 100 / this.barItems.length;
30158 Roo.each(this.barItems, function(i){
30159 i.el.setStyle('width', width + '%');
30160 i.topEl.el.setStyle('width', width + '%');
30161 i.bottomEl.el.setStyle('width', width + '%');
30170 * Nav Progress Item
30175 * @class Roo.bootstrap.NavProgressItem
30176 * @extends Roo.bootstrap.Component
30177 * Bootstrap NavProgressItem class
30178 * @cfg {String} rid the reference id
30179 * @cfg {Boolean} active (true|false) Is item active default false
30180 * @cfg {Boolean} disabled (true|false) Is item active default false
30181 * @cfg {String} html
30182 * @cfg {String} position (top|bottom) text position default bottom
30183 * @cfg {String} icon show icon instead of number
30186 * Create a new NavProgressItem
30187 * @param {Object} config The config object
30189 Roo.bootstrap.NavProgressItem = function(config){
30190 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30195 * The raw click event for the entire grid.
30196 * @param {Roo.bootstrap.NavProgressItem} this
30197 * @param {Roo.EventObject} e
30204 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30210 position : 'bottom',
30213 getAutoCreate : function()
30215 var iconCls = 'roo-navigation-bar-item-icon';
30217 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30221 cls: 'roo-navigation-bar-item',
30231 cfg.cls += ' active';
30234 cfg.cls += ' disabled';
30240 disable : function()
30242 this.setDisabled(true);
30245 enable : function()
30247 this.setDisabled(false);
30250 initEvents: function()
30252 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30254 this.iconEl.on('click', this.onClick, this);
30257 onClick : function(e)
30259 e.preventDefault();
30265 if(this.fireEvent('click', this, e) === false){
30269 this.parent().setActiveItem(this);
30272 isActive: function ()
30274 return this.active;
30277 setActive : function(state)
30279 if(this.active == state){
30283 this.active = state;
30286 this.el.addClass('active');
30290 this.el.removeClass('active');
30295 setDisabled : function(state)
30297 if(this.disabled == state){
30301 this.disabled = state;
30304 this.el.addClass('disabled');
30308 this.el.removeClass('disabled');
30311 tooltipEl : function()
30313 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30326 * @class Roo.bootstrap.FieldLabel
30327 * @extends Roo.bootstrap.Component
30328 * Bootstrap FieldLabel class
30329 * @cfg {String} html contents of the element
30330 * @cfg {String} tag tag of the element default label
30331 * @cfg {String} cls class of the element
30332 * @cfg {String} target label target
30333 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30334 * @cfg {String} invalidClass default "text-warning"
30335 * @cfg {String} validClass default "text-success"
30336 * @cfg {String} iconTooltip default "This field is required"
30337 * @cfg {String} indicatorpos (left|right) default left
30340 * Create a new FieldLabel
30341 * @param {Object} config The config object
30344 Roo.bootstrap.FieldLabel = function(config){
30345 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30350 * Fires after the field has been marked as invalid.
30351 * @param {Roo.form.FieldLabel} this
30352 * @param {String} msg The validation message
30357 * Fires after the field has been validated with no errors.
30358 * @param {Roo.form.FieldLabel} this
30364 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30371 invalidClass : 'has-warning',
30372 validClass : 'has-success',
30373 iconTooltip : 'This field is required',
30374 indicatorpos : 'left',
30376 getAutoCreate : function(){
30379 if (!this.allowBlank) {
30385 cls : 'roo-bootstrap-field-label ' + this.cls,
30390 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30391 tooltip : this.iconTooltip
30400 if(this.indicatorpos == 'right'){
30403 cls : 'roo-bootstrap-field-label ' + this.cls,
30412 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30413 tooltip : this.iconTooltip
30422 initEvents: function()
30424 Roo.bootstrap.Element.superclass.initEvents.call(this);
30426 this.indicator = this.indicatorEl();
30428 if(this.indicator){
30429 this.indicator.removeClass('visible');
30430 this.indicator.addClass('invisible');
30433 Roo.bootstrap.FieldLabel.register(this);
30436 indicatorEl : function()
30438 var indicator = this.el.select('i.roo-required-indicator',true).first();
30449 * Mark this field as valid
30451 markValid : function()
30453 if(this.indicator){
30454 this.indicator.removeClass('visible');
30455 this.indicator.addClass('invisible');
30458 this.el.removeClass(this.invalidClass);
30460 this.el.addClass(this.validClass);
30462 this.fireEvent('valid', this);
30466 * Mark this field as invalid
30467 * @param {String} msg The validation message
30469 markInvalid : function(msg)
30471 if(this.indicator){
30472 this.indicator.removeClass('invisible');
30473 this.indicator.addClass('visible');
30476 this.el.removeClass(this.validClass);
30478 this.el.addClass(this.invalidClass);
30480 this.fireEvent('invalid', this, msg);
30486 Roo.apply(Roo.bootstrap.FieldLabel, {
30491 * register a FieldLabel Group
30492 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30494 register : function(label)
30496 if(this.groups.hasOwnProperty(label.target)){
30500 this.groups[label.target] = label;
30504 * fetch a FieldLabel Group based on the target
30505 * @param {string} target
30506 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30508 get: function(target) {
30509 if (typeof(this.groups[target]) == 'undefined') {
30513 return this.groups[target] ;
30522 * page DateSplitField.
30528 * @class Roo.bootstrap.DateSplitField
30529 * @extends Roo.bootstrap.Component
30530 * Bootstrap DateSplitField class
30531 * @cfg {string} fieldLabel - the label associated
30532 * @cfg {Number} labelWidth set the width of label (0-12)
30533 * @cfg {String} labelAlign (top|left)
30534 * @cfg {Boolean} dayAllowBlank (true|false) default false
30535 * @cfg {Boolean} monthAllowBlank (true|false) default false
30536 * @cfg {Boolean} yearAllowBlank (true|false) default false
30537 * @cfg {string} dayPlaceholder
30538 * @cfg {string} monthPlaceholder
30539 * @cfg {string} yearPlaceholder
30540 * @cfg {string} dayFormat default 'd'
30541 * @cfg {string} monthFormat default 'm'
30542 * @cfg {string} yearFormat default 'Y'
30543 * @cfg {Number} labellg set the width of label (1-12)
30544 * @cfg {Number} labelmd set the width of label (1-12)
30545 * @cfg {Number} labelsm set the width of label (1-12)
30546 * @cfg {Number} labelxs set the width of label (1-12)
30550 * Create a new DateSplitField
30551 * @param {Object} config The config object
30554 Roo.bootstrap.DateSplitField = function(config){
30555 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30561 * getting the data of years
30562 * @param {Roo.bootstrap.DateSplitField} this
30563 * @param {Object} years
30568 * getting the data of days
30569 * @param {Roo.bootstrap.DateSplitField} this
30570 * @param {Object} days
30575 * Fires after the field has been marked as invalid.
30576 * @param {Roo.form.Field} this
30577 * @param {String} msg The validation message
30582 * Fires after the field has been validated with no errors.
30583 * @param {Roo.form.Field} this
30589 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30592 labelAlign : 'top',
30594 dayAllowBlank : false,
30595 monthAllowBlank : false,
30596 yearAllowBlank : false,
30597 dayPlaceholder : '',
30598 monthPlaceholder : '',
30599 yearPlaceholder : '',
30603 isFormField : true,
30609 getAutoCreate : function()
30613 cls : 'row roo-date-split-field-group',
30618 cls : 'form-hidden-field roo-date-split-field-group-value',
30624 var labelCls = 'col-md-12';
30625 var contentCls = 'col-md-4';
30627 if(this.fieldLabel){
30631 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30635 html : this.fieldLabel
30640 if(this.labelAlign == 'left'){
30642 if(this.labelWidth > 12){
30643 label.style = "width: " + this.labelWidth + 'px';
30646 if(this.labelWidth < 13 && this.labelmd == 0){
30647 this.labelmd = this.labelWidth;
30650 if(this.labellg > 0){
30651 labelCls = ' col-lg-' + this.labellg;
30652 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30655 if(this.labelmd > 0){
30656 labelCls = ' col-md-' + this.labelmd;
30657 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30660 if(this.labelsm > 0){
30661 labelCls = ' col-sm-' + this.labelsm;
30662 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30665 if(this.labelxs > 0){
30666 labelCls = ' col-xs-' + this.labelxs;
30667 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30671 label.cls += ' ' + labelCls;
30673 cfg.cn.push(label);
30676 Roo.each(['day', 'month', 'year'], function(t){
30679 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30686 inputEl: function ()
30688 return this.el.select('.roo-date-split-field-group-value', true).first();
30691 onRender : function(ct, position)
30695 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30697 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30699 this.dayField = new Roo.bootstrap.ComboBox({
30700 allowBlank : this.dayAllowBlank,
30701 alwaysQuery : true,
30702 displayField : 'value',
30705 forceSelection : true,
30707 placeholder : this.dayPlaceholder,
30708 selectOnFocus : true,
30709 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30710 triggerAction : 'all',
30712 valueField : 'value',
30713 store : new Roo.data.SimpleStore({
30714 data : (function() {
30716 _this.fireEvent('days', _this, days);
30719 fields : [ 'value' ]
30722 select : function (_self, record, index)
30724 _this.setValue(_this.getValue());
30729 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30731 this.monthField = new Roo.bootstrap.MonthField({
30732 after : '<i class=\"fa fa-calendar\"></i>',
30733 allowBlank : this.monthAllowBlank,
30734 placeholder : this.monthPlaceholder,
30737 render : function (_self)
30739 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30740 e.preventDefault();
30744 select : function (_self, oldvalue, newvalue)
30746 _this.setValue(_this.getValue());
30751 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30753 this.yearField = new Roo.bootstrap.ComboBox({
30754 allowBlank : this.yearAllowBlank,
30755 alwaysQuery : true,
30756 displayField : 'value',
30759 forceSelection : true,
30761 placeholder : this.yearPlaceholder,
30762 selectOnFocus : true,
30763 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30764 triggerAction : 'all',
30766 valueField : 'value',
30767 store : new Roo.data.SimpleStore({
30768 data : (function() {
30770 _this.fireEvent('years', _this, years);
30773 fields : [ 'value' ]
30776 select : function (_self, record, index)
30778 _this.setValue(_this.getValue());
30783 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30786 setValue : function(v, format)
30788 this.inputEl.dom.value = v;
30790 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30792 var d = Date.parseDate(v, f);
30799 this.setDay(d.format(this.dayFormat));
30800 this.setMonth(d.format(this.monthFormat));
30801 this.setYear(d.format(this.yearFormat));
30808 setDay : function(v)
30810 this.dayField.setValue(v);
30811 this.inputEl.dom.value = this.getValue();
30816 setMonth : function(v)
30818 this.monthField.setValue(v, true);
30819 this.inputEl.dom.value = this.getValue();
30824 setYear : function(v)
30826 this.yearField.setValue(v);
30827 this.inputEl.dom.value = this.getValue();
30832 getDay : function()
30834 return this.dayField.getValue();
30837 getMonth : function()
30839 return this.monthField.getValue();
30842 getYear : function()
30844 return this.yearField.getValue();
30847 getValue : function()
30849 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30851 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30861 this.inputEl.dom.value = '';
30866 validate : function()
30868 var d = this.dayField.validate();
30869 var m = this.monthField.validate();
30870 var y = this.yearField.validate();
30875 (!this.dayAllowBlank && !d) ||
30876 (!this.monthAllowBlank && !m) ||
30877 (!this.yearAllowBlank && !y)
30882 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30891 this.markInvalid();
30896 markValid : function()
30899 var label = this.el.select('label', true).first();
30900 var icon = this.el.select('i.fa-star', true).first();
30906 this.fireEvent('valid', this);
30910 * Mark this field as invalid
30911 * @param {String} msg The validation message
30913 markInvalid : function(msg)
30916 var label = this.el.select('label', true).first();
30917 var icon = this.el.select('i.fa-star', true).first();
30919 if(label && !icon){
30920 this.el.select('.roo-date-split-field-label', true).createChild({
30922 cls : 'text-danger fa fa-lg fa-star',
30923 tooltip : 'This field is required',
30924 style : 'margin-right:5px;'
30928 this.fireEvent('invalid', this, msg);
30931 clearInvalid : function()
30933 var label = this.el.select('label', true).first();
30934 var icon = this.el.select('i.fa-star', true).first();
30940 this.fireEvent('valid', this);
30943 getName: function()
30953 * http://masonry.desandro.com
30955 * The idea is to render all the bricks based on vertical width...
30957 * The original code extends 'outlayer' - we might need to use that....
30963 * @class Roo.bootstrap.LayoutMasonry
30964 * @extends Roo.bootstrap.Component
30965 * Bootstrap Layout Masonry class
30968 * Create a new Element
30969 * @param {Object} config The config object
30972 Roo.bootstrap.LayoutMasonry = function(config){
30974 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30978 Roo.bootstrap.LayoutMasonry.register(this);
30984 * Fire after layout the items
30985 * @param {Roo.bootstrap.LayoutMasonry} this
30986 * @param {Roo.EventObject} e
30993 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30996 * @cfg {Boolean} isLayoutInstant = no animation?
30998 isLayoutInstant : false, // needed?
31001 * @cfg {Number} boxWidth width of the columns
31006 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31011 * @cfg {Number} padWidth padding below box..
31016 * @cfg {Number} gutter gutter width..
31021 * @cfg {Number} maxCols maximum number of columns
31027 * @cfg {Boolean} isAutoInitial defalut true
31029 isAutoInitial : true,
31034 * @cfg {Boolean} isHorizontal defalut false
31036 isHorizontal : false,
31038 currentSize : null,
31044 bricks: null, //CompositeElement
31048 _isLayoutInited : false,
31050 // isAlternative : false, // only use for vertical layout...
31053 * @cfg {Number} alternativePadWidth padding below box..
31055 alternativePadWidth : 50,
31057 selectedBrick : [],
31059 getAutoCreate : function(){
31061 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31065 cls: 'blog-masonary-wrapper ' + this.cls,
31067 cls : 'mas-boxes masonary'
31074 getChildContainer: function( )
31076 if (this.boxesEl) {
31077 return this.boxesEl;
31080 this.boxesEl = this.el.select('.mas-boxes').first();
31082 return this.boxesEl;
31086 initEvents : function()
31090 if(this.isAutoInitial){
31091 Roo.log('hook children rendered');
31092 this.on('childrenrendered', function() {
31093 Roo.log('children rendered');
31099 initial : function()
31101 this.selectedBrick = [];
31103 this.currentSize = this.el.getBox(true);
31105 Roo.EventManager.onWindowResize(this.resize, this);
31107 if(!this.isAutoInitial){
31115 //this.layout.defer(500,this);
31119 resize : function()
31121 var cs = this.el.getBox(true);
31124 this.currentSize.width == cs.width &&
31125 this.currentSize.x == cs.x &&
31126 this.currentSize.height == cs.height &&
31127 this.currentSize.y == cs.y
31129 Roo.log("no change in with or X or Y");
31133 this.currentSize = cs;
31139 layout : function()
31141 this._resetLayout();
31143 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31145 this.layoutItems( isInstant );
31147 this._isLayoutInited = true;
31149 this.fireEvent('layout', this);
31153 _resetLayout : function()
31155 if(this.isHorizontal){
31156 this.horizontalMeasureColumns();
31160 this.verticalMeasureColumns();
31164 verticalMeasureColumns : function()
31166 this.getContainerWidth();
31168 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31169 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31173 var boxWidth = this.boxWidth + this.padWidth;
31175 if(this.containerWidth < this.boxWidth){
31176 boxWidth = this.containerWidth
31179 var containerWidth = this.containerWidth;
31181 var cols = Math.floor(containerWidth / boxWidth);
31183 this.cols = Math.max( cols, 1 );
31185 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31187 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31189 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31191 this.colWidth = boxWidth + avail - this.padWidth;
31193 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31194 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31197 horizontalMeasureColumns : function()
31199 this.getContainerWidth();
31201 var boxWidth = this.boxWidth;
31203 if(this.containerWidth < boxWidth){
31204 boxWidth = this.containerWidth;
31207 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31209 this.el.setHeight(boxWidth);
31213 getContainerWidth : function()
31215 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31218 layoutItems : function( isInstant )
31220 Roo.log(this.bricks);
31222 var items = Roo.apply([], this.bricks);
31224 if(this.isHorizontal){
31225 this._horizontalLayoutItems( items , isInstant );
31229 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31230 // this._verticalAlternativeLayoutItems( items , isInstant );
31234 this._verticalLayoutItems( items , isInstant );
31238 _verticalLayoutItems : function ( items , isInstant)
31240 if ( !items || !items.length ) {
31245 ['xs', 'xs', 'xs', 'tall'],
31246 ['xs', 'xs', 'tall'],
31247 ['xs', 'xs', 'sm'],
31248 ['xs', 'xs', 'xs'],
31254 ['sm', 'xs', 'xs'],
31258 ['tall', 'xs', 'xs', 'xs'],
31259 ['tall', 'xs', 'xs'],
31271 Roo.each(items, function(item, k){
31273 switch (item.size) {
31274 // these layouts take up a full box,
31285 boxes.push([item]);
31308 var filterPattern = function(box, length)
31316 var pattern = box.slice(0, length);
31320 Roo.each(pattern, function(i){
31321 format.push(i.size);
31324 Roo.each(standard, function(s){
31326 if(String(s) != String(format)){
31335 if(!match && length == 1){
31340 filterPattern(box, length - 1);
31344 queue.push(pattern);
31346 box = box.slice(length, box.length);
31348 filterPattern(box, 4);
31354 Roo.each(boxes, function(box, k){
31360 if(box.length == 1){
31365 filterPattern(box, 4);
31369 this._processVerticalLayoutQueue( queue, isInstant );
31373 // _verticalAlternativeLayoutItems : function( items , isInstant )
31375 // if ( !items || !items.length ) {
31379 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31383 _horizontalLayoutItems : function ( items , isInstant)
31385 if ( !items || !items.length || items.length < 3) {
31391 var eItems = items.slice(0, 3);
31393 items = items.slice(3, items.length);
31396 ['xs', 'xs', 'xs', 'wide'],
31397 ['xs', 'xs', 'wide'],
31398 ['xs', 'xs', 'sm'],
31399 ['xs', 'xs', 'xs'],
31405 ['sm', 'xs', 'xs'],
31409 ['wide', 'xs', 'xs', 'xs'],
31410 ['wide', 'xs', 'xs'],
31423 Roo.each(items, function(item, k){
31425 switch (item.size) {
31436 boxes.push([item]);
31460 var filterPattern = function(box, length)
31468 var pattern = box.slice(0, length);
31472 Roo.each(pattern, function(i){
31473 format.push(i.size);
31476 Roo.each(standard, function(s){
31478 if(String(s) != String(format)){
31487 if(!match && length == 1){
31492 filterPattern(box, length - 1);
31496 queue.push(pattern);
31498 box = box.slice(length, box.length);
31500 filterPattern(box, 4);
31506 Roo.each(boxes, function(box, k){
31512 if(box.length == 1){
31517 filterPattern(box, 4);
31524 var pos = this.el.getBox(true);
31528 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31530 var hit_end = false;
31532 Roo.each(queue, function(box){
31536 Roo.each(box, function(b){
31538 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31548 Roo.each(box, function(b){
31550 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31553 mx = Math.max(mx, b.x);
31557 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31561 Roo.each(box, function(b){
31563 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31577 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31580 /** Sets position of item in DOM
31581 * @param {Element} item
31582 * @param {Number} x - horizontal position
31583 * @param {Number} y - vertical position
31584 * @param {Boolean} isInstant - disables transitions
31586 _processVerticalLayoutQueue : function( queue, isInstant )
31588 var pos = this.el.getBox(true);
31593 for (var i = 0; i < this.cols; i++){
31597 Roo.each(queue, function(box, k){
31599 var col = k % this.cols;
31601 Roo.each(box, function(b,kk){
31603 b.el.position('absolute');
31605 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31606 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31608 if(b.size == 'md-left' || b.size == 'md-right'){
31609 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31610 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31613 b.el.setWidth(width);
31614 b.el.setHeight(height);
31616 b.el.select('iframe',true).setSize(width,height);
31620 for (var i = 0; i < this.cols; i++){
31622 if(maxY[i] < maxY[col]){
31627 col = Math.min(col, i);
31631 x = pos.x + col * (this.colWidth + this.padWidth);
31635 var positions = [];
31637 switch (box.length){
31639 positions = this.getVerticalOneBoxColPositions(x, y, box);
31642 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31645 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31648 positions = this.getVerticalFourBoxColPositions(x, y, box);
31654 Roo.each(box, function(b,kk){
31656 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31658 var sz = b.el.getSize();
31660 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31668 for (var i = 0; i < this.cols; i++){
31669 mY = Math.max(mY, maxY[i]);
31672 this.el.setHeight(mY - pos.y);
31676 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31678 // var pos = this.el.getBox(true);
31681 // var maxX = pos.right;
31683 // var maxHeight = 0;
31685 // Roo.each(items, function(item, k){
31689 // item.el.position('absolute');
31691 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31693 // item.el.setWidth(width);
31695 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31697 // item.el.setHeight(height);
31700 // item.el.setXY([x, y], isInstant ? false : true);
31702 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31705 // y = y + height + this.alternativePadWidth;
31707 // maxHeight = maxHeight + height + this.alternativePadWidth;
31711 // this.el.setHeight(maxHeight);
31715 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31717 var pos = this.el.getBox(true);
31722 var maxX = pos.right;
31724 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31726 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31728 Roo.each(queue, function(box, k){
31730 Roo.each(box, function(b, kk){
31732 b.el.position('absolute');
31734 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31735 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31737 if(b.size == 'md-left' || b.size == 'md-right'){
31738 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31739 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31742 b.el.setWidth(width);
31743 b.el.setHeight(height);
31751 var positions = [];
31753 switch (box.length){
31755 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31758 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31761 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31764 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31770 Roo.each(box, function(b,kk){
31772 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31774 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31782 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31784 Roo.each(eItems, function(b,k){
31786 b.size = (k == 0) ? 'sm' : 'xs';
31787 b.x = (k == 0) ? 2 : 1;
31788 b.y = (k == 0) ? 2 : 1;
31790 b.el.position('absolute');
31792 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31794 b.el.setWidth(width);
31796 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31798 b.el.setHeight(height);
31802 var positions = [];
31805 x : maxX - this.unitWidth * 2 - this.gutter,
31810 x : maxX - this.unitWidth,
31811 y : minY + (this.unitWidth + this.gutter) * 2
31815 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31819 Roo.each(eItems, function(b,k){
31821 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31827 getVerticalOneBoxColPositions : function(x, y, box)
31831 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31833 if(box[0].size == 'md-left'){
31837 if(box[0].size == 'md-right'){
31842 x : x + (this.unitWidth + this.gutter) * rand,
31849 getVerticalTwoBoxColPositions : function(x, y, box)
31853 if(box[0].size == 'xs'){
31857 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31861 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31875 x : x + (this.unitWidth + this.gutter) * 2,
31876 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31883 getVerticalThreeBoxColPositions : function(x, y, box)
31887 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31895 x : x + (this.unitWidth + this.gutter) * 1,
31900 x : x + (this.unitWidth + this.gutter) * 2,
31908 if(box[0].size == 'xs' && box[1].size == 'xs'){
31917 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31921 x : x + (this.unitWidth + this.gutter) * 1,
31935 x : x + (this.unitWidth + this.gutter) * 2,
31940 x : x + (this.unitWidth + this.gutter) * 2,
31941 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31948 getVerticalFourBoxColPositions : function(x, y, box)
31952 if(box[0].size == 'xs'){
31961 y : y + (this.unitHeight + this.gutter) * 1
31966 y : y + (this.unitHeight + this.gutter) * 2
31970 x : x + (this.unitWidth + this.gutter) * 1,
31984 x : x + (this.unitWidth + this.gutter) * 2,
31989 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31990 y : y + (this.unitHeight + this.gutter) * 1
31994 x : x + (this.unitWidth + this.gutter) * 2,
31995 y : y + (this.unitWidth + this.gutter) * 2
32002 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32006 if(box[0].size == 'md-left'){
32008 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32015 if(box[0].size == 'md-right'){
32017 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32018 y : minY + (this.unitWidth + this.gutter) * 1
32024 var rand = Math.floor(Math.random() * (4 - box[0].y));
32027 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32028 y : minY + (this.unitWidth + this.gutter) * rand
32035 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32039 if(box[0].size == 'xs'){
32042 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32047 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32048 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32056 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32061 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32062 y : minY + (this.unitWidth + this.gutter) * 2
32069 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32073 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32076 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32081 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32082 y : minY + (this.unitWidth + this.gutter) * 1
32086 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32087 y : minY + (this.unitWidth + this.gutter) * 2
32094 if(box[0].size == 'xs' && box[1].size == 'xs'){
32097 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32102 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32107 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32108 y : minY + (this.unitWidth + this.gutter) * 1
32116 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32121 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32122 y : minY + (this.unitWidth + this.gutter) * 2
32126 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32127 y : minY + (this.unitWidth + this.gutter) * 2
32134 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32138 if(box[0].size == 'xs'){
32141 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32146 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32151 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),
32156 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32157 y : minY + (this.unitWidth + this.gutter) * 1
32165 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32170 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32171 y : minY + (this.unitWidth + this.gutter) * 2
32175 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32176 y : minY + (this.unitWidth + this.gutter) * 2
32180 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),
32181 y : minY + (this.unitWidth + this.gutter) * 2
32189 * remove a Masonry Brick
32190 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32192 removeBrick : function(brick_id)
32198 for (var i = 0; i<this.bricks.length; i++) {
32199 if (this.bricks[i].id == brick_id) {
32200 this.bricks.splice(i,1);
32201 this.el.dom.removeChild(Roo.get(brick_id).dom);
32208 * adds a Masonry Brick
32209 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32211 addBrick : function(cfg)
32213 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32214 //this.register(cn);
32215 cn.parentId = this.id;
32216 cn.render(this.el);
32221 * register a Masonry Brick
32222 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32225 register : function(brick)
32227 this.bricks.push(brick);
32228 brick.masonryId = this.id;
32232 * clear all the Masonry Brick
32234 clearAll : function()
32237 //this.getChildContainer().dom.innerHTML = "";
32238 this.el.dom.innerHTML = '';
32241 getSelected : function()
32243 if (!this.selectedBrick) {
32247 return this.selectedBrick;
32251 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32255 * register a Masonry Layout
32256 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32259 register : function(layout)
32261 this.groups[layout.id] = layout;
32264 * fetch a Masonry Layout based on the masonry layout ID
32265 * @param {string} the masonry layout to add
32266 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32269 get: function(layout_id) {
32270 if (typeof(this.groups[layout_id]) == 'undefined') {
32273 return this.groups[layout_id] ;
32285 * http://masonry.desandro.com
32287 * The idea is to render all the bricks based on vertical width...
32289 * The original code extends 'outlayer' - we might need to use that....
32295 * @class Roo.bootstrap.LayoutMasonryAuto
32296 * @extends Roo.bootstrap.Component
32297 * Bootstrap Layout Masonry class
32300 * Create a new Element
32301 * @param {Object} config The config object
32304 Roo.bootstrap.LayoutMasonryAuto = function(config){
32305 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32308 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32311 * @cfg {Boolean} isFitWidth - resize the width..
32313 isFitWidth : false, // options..
32315 * @cfg {Boolean} isOriginLeft = left align?
32317 isOriginLeft : true,
32319 * @cfg {Boolean} isOriginTop = top align?
32321 isOriginTop : false,
32323 * @cfg {Boolean} isLayoutInstant = no animation?
32325 isLayoutInstant : false, // needed?
32327 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32329 isResizingContainer : true,
32331 * @cfg {Number} columnWidth width of the columns
32337 * @cfg {Number} maxCols maximum number of columns
32342 * @cfg {Number} padHeight padding below box..
32348 * @cfg {Boolean} isAutoInitial defalut true
32351 isAutoInitial : true,
32357 initialColumnWidth : 0,
32358 currentSize : null,
32360 colYs : null, // array.
32367 bricks: null, //CompositeElement
32368 cols : 0, // array?
32369 // element : null, // wrapped now this.el
32370 _isLayoutInited : null,
32373 getAutoCreate : function(){
32377 cls: 'blog-masonary-wrapper ' + this.cls,
32379 cls : 'mas-boxes masonary'
32386 getChildContainer: function( )
32388 if (this.boxesEl) {
32389 return this.boxesEl;
32392 this.boxesEl = this.el.select('.mas-boxes').first();
32394 return this.boxesEl;
32398 initEvents : function()
32402 if(this.isAutoInitial){
32403 Roo.log('hook children rendered');
32404 this.on('childrenrendered', function() {
32405 Roo.log('children rendered');
32412 initial : function()
32414 this.reloadItems();
32416 this.currentSize = this.el.getBox(true);
32418 /// was window resize... - let's see if this works..
32419 Roo.EventManager.onWindowResize(this.resize, this);
32421 if(!this.isAutoInitial){
32426 this.layout.defer(500,this);
32429 reloadItems: function()
32431 this.bricks = this.el.select('.masonry-brick', true);
32433 this.bricks.each(function(b) {
32434 //Roo.log(b.getSize());
32435 if (!b.attr('originalwidth')) {
32436 b.attr('originalwidth', b.getSize().width);
32441 Roo.log(this.bricks.elements.length);
32444 resize : function()
32447 var cs = this.el.getBox(true);
32449 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32450 Roo.log("no change in with or X");
32453 this.currentSize = cs;
32457 layout : function()
32460 this._resetLayout();
32461 //this._manageStamps();
32463 // don't animate first layout
32464 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32465 this.layoutItems( isInstant );
32467 // flag for initalized
32468 this._isLayoutInited = true;
32471 layoutItems : function( isInstant )
32473 //var items = this._getItemsForLayout( this.items );
32474 // original code supports filtering layout items.. we just ignore it..
32476 this._layoutItems( this.bricks , isInstant );
32478 this._postLayout();
32480 _layoutItems : function ( items , isInstant)
32482 //this.fireEvent( 'layout', this, items );
32485 if ( !items || !items.elements.length ) {
32486 // no items, emit event with empty array
32491 items.each(function(item) {
32492 Roo.log("layout item");
32494 // get x/y object from method
32495 var position = this._getItemLayoutPosition( item );
32497 position.item = item;
32498 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32499 queue.push( position );
32502 this._processLayoutQueue( queue );
32504 /** Sets position of item in DOM
32505 * @param {Element} item
32506 * @param {Number} x - horizontal position
32507 * @param {Number} y - vertical position
32508 * @param {Boolean} isInstant - disables transitions
32510 _processLayoutQueue : function( queue )
32512 for ( var i=0, len = queue.length; i < len; i++ ) {
32513 var obj = queue[i];
32514 obj.item.position('absolute');
32515 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32521 * Any logic you want to do after each layout,
32522 * i.e. size the container
32524 _postLayout : function()
32526 this.resizeContainer();
32529 resizeContainer : function()
32531 if ( !this.isResizingContainer ) {
32534 var size = this._getContainerSize();
32536 this.el.setSize(size.width,size.height);
32537 this.boxesEl.setSize(size.width,size.height);
32543 _resetLayout : function()
32545 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32546 this.colWidth = this.el.getWidth();
32547 //this.gutter = this.el.getWidth();
32549 this.measureColumns();
32555 this.colYs.push( 0 );
32561 measureColumns : function()
32563 this.getContainerWidth();
32564 // if columnWidth is 0, default to outerWidth of first item
32565 if ( !this.columnWidth ) {
32566 var firstItem = this.bricks.first();
32567 Roo.log(firstItem);
32568 this.columnWidth = this.containerWidth;
32569 if (firstItem && firstItem.attr('originalwidth') ) {
32570 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32572 // columnWidth fall back to item of first element
32573 Roo.log("set column width?");
32574 this.initialColumnWidth = this.columnWidth ;
32576 // if first elem has no width, default to size of container
32581 if (this.initialColumnWidth) {
32582 this.columnWidth = this.initialColumnWidth;
32587 // column width is fixed at the top - however if container width get's smaller we should
32590 // this bit calcs how man columns..
32592 var columnWidth = this.columnWidth += this.gutter;
32594 // calculate columns
32595 var containerWidth = this.containerWidth + this.gutter;
32597 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32598 // fix rounding errors, typically with gutters
32599 var excess = columnWidth - containerWidth % columnWidth;
32602 // if overshoot is less than a pixel, round up, otherwise floor it
32603 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32604 cols = Math[ mathMethod ]( cols );
32605 this.cols = Math.max( cols, 1 );
32606 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32608 // padding positioning..
32609 var totalColWidth = this.cols * this.columnWidth;
32610 var padavail = this.containerWidth - totalColWidth;
32611 // so for 2 columns - we need 3 'pads'
32613 var padNeeded = (1+this.cols) * this.padWidth;
32615 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32617 this.columnWidth += padExtra
32618 //this.padWidth = Math.floor(padavail / ( this.cols));
32620 // adjust colum width so that padding is fixed??
32622 // we have 3 columns ... total = width * 3
32623 // we have X left over... that should be used by
32625 //if (this.expandC) {
32633 getContainerWidth : function()
32635 /* // container is parent if fit width
32636 var container = this.isFitWidth ? this.element.parentNode : this.element;
32637 // check that this.size and size are there
32638 // IE8 triggers resize on body size change, so they might not be
32640 var size = getSize( container ); //FIXME
32641 this.containerWidth = size && size.innerWidth; //FIXME
32644 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32648 _getItemLayoutPosition : function( item ) // what is item?
32650 // we resize the item to our columnWidth..
32652 item.setWidth(this.columnWidth);
32653 item.autoBoxAdjust = false;
32655 var sz = item.getSize();
32657 // how many columns does this brick span
32658 var remainder = this.containerWidth % this.columnWidth;
32660 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32661 // round if off by 1 pixel, otherwise use ceil
32662 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32663 colSpan = Math.min( colSpan, this.cols );
32665 // normally this should be '1' as we dont' currently allow multi width columns..
32667 var colGroup = this._getColGroup( colSpan );
32668 // get the minimum Y value from the columns
32669 var minimumY = Math.min.apply( Math, colGroup );
32670 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32672 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32674 // position the brick
32676 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32677 y: this.currentSize.y + minimumY + this.padHeight
32681 // apply setHeight to necessary columns
32682 var setHeight = minimumY + sz.height + this.padHeight;
32683 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32685 var setSpan = this.cols + 1 - colGroup.length;
32686 for ( var i = 0; i < setSpan; i++ ) {
32687 this.colYs[ shortColIndex + i ] = setHeight ;
32694 * @param {Number} colSpan - number of columns the element spans
32695 * @returns {Array} colGroup
32697 _getColGroup : function( colSpan )
32699 if ( colSpan < 2 ) {
32700 // if brick spans only one column, use all the column Ys
32705 // how many different places could this brick fit horizontally
32706 var groupCount = this.cols + 1 - colSpan;
32707 // for each group potential horizontal position
32708 for ( var i = 0; i < groupCount; i++ ) {
32709 // make an array of colY values for that one group
32710 var groupColYs = this.colYs.slice( i, i + colSpan );
32711 // and get the max value of the array
32712 colGroup[i] = Math.max.apply( Math, groupColYs );
32717 _manageStamp : function( stamp )
32719 var stampSize = stamp.getSize();
32720 var offset = stamp.getBox();
32721 // get the columns that this stamp affects
32722 var firstX = this.isOriginLeft ? offset.x : offset.right;
32723 var lastX = firstX + stampSize.width;
32724 var firstCol = Math.floor( firstX / this.columnWidth );
32725 firstCol = Math.max( 0, firstCol );
32727 var lastCol = Math.floor( lastX / this.columnWidth );
32728 // lastCol should not go over if multiple of columnWidth #425
32729 lastCol -= lastX % this.columnWidth ? 0 : 1;
32730 lastCol = Math.min( this.cols - 1, lastCol );
32732 // set colYs to bottom of the stamp
32733 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32736 for ( var i = firstCol; i <= lastCol; i++ ) {
32737 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32742 _getContainerSize : function()
32744 this.maxY = Math.max.apply( Math, this.colYs );
32749 if ( this.isFitWidth ) {
32750 size.width = this._getContainerFitWidth();
32756 _getContainerFitWidth : function()
32758 var unusedCols = 0;
32759 // count unused columns
32762 if ( this.colYs[i] !== 0 ) {
32767 // fit container to columns that have been used
32768 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32771 needsResizeLayout : function()
32773 var previousWidth = this.containerWidth;
32774 this.getContainerWidth();
32775 return previousWidth !== this.containerWidth;
32790 * @class Roo.bootstrap.MasonryBrick
32791 * @extends Roo.bootstrap.Component
32792 * Bootstrap MasonryBrick class
32795 * Create a new MasonryBrick
32796 * @param {Object} config The config object
32799 Roo.bootstrap.MasonryBrick = function(config){
32801 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32803 Roo.bootstrap.MasonryBrick.register(this);
32809 * When a MasonryBrick is clcik
32810 * @param {Roo.bootstrap.MasonryBrick} this
32811 * @param {Roo.EventObject} e
32817 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32820 * @cfg {String} title
32824 * @cfg {String} html
32828 * @cfg {String} bgimage
32832 * @cfg {String} videourl
32836 * @cfg {String} cls
32840 * @cfg {String} href
32844 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32849 * @cfg {String} placetitle (center|bottom)
32854 * @cfg {Boolean} isFitContainer defalut true
32856 isFitContainer : true,
32859 * @cfg {Boolean} preventDefault defalut false
32861 preventDefault : false,
32864 * @cfg {Boolean} inverse defalut false
32866 maskInverse : false,
32868 getAutoCreate : function()
32870 if(!this.isFitContainer){
32871 return this.getSplitAutoCreate();
32874 var cls = 'masonry-brick masonry-brick-full';
32876 if(this.href.length){
32877 cls += ' masonry-brick-link';
32880 if(this.bgimage.length){
32881 cls += ' masonry-brick-image';
32884 if(this.maskInverse){
32885 cls += ' mask-inverse';
32888 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32889 cls += ' enable-mask';
32893 cls += ' masonry-' + this.size + '-brick';
32896 if(this.placetitle.length){
32898 switch (this.placetitle) {
32900 cls += ' masonry-center-title';
32903 cls += ' masonry-bottom-title';
32910 if(!this.html.length && !this.bgimage.length){
32911 cls += ' masonry-center-title';
32914 if(!this.html.length && this.bgimage.length){
32915 cls += ' masonry-bottom-title';
32920 cls += ' ' + this.cls;
32924 tag: (this.href.length) ? 'a' : 'div',
32929 cls: 'masonry-brick-mask'
32933 cls: 'masonry-brick-paragraph',
32939 if(this.href.length){
32940 cfg.href = this.href;
32943 var cn = cfg.cn[1].cn;
32945 if(this.title.length){
32948 cls: 'masonry-brick-title',
32953 if(this.html.length){
32956 cls: 'masonry-brick-text',
32961 if (!this.title.length && !this.html.length) {
32962 cfg.cn[1].cls += ' hide';
32965 if(this.bgimage.length){
32968 cls: 'masonry-brick-image-view',
32973 if(this.videourl.length){
32974 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32975 // youtube support only?
32978 cls: 'masonry-brick-image-view',
32981 allowfullscreen : true
32989 getSplitAutoCreate : function()
32991 var cls = 'masonry-brick masonry-brick-split';
32993 if(this.href.length){
32994 cls += ' masonry-brick-link';
32997 if(this.bgimage.length){
32998 cls += ' masonry-brick-image';
33002 cls += ' masonry-' + this.size + '-brick';
33005 switch (this.placetitle) {
33007 cls += ' masonry-center-title';
33010 cls += ' masonry-bottom-title';
33013 if(!this.bgimage.length){
33014 cls += ' masonry-center-title';
33017 if(this.bgimage.length){
33018 cls += ' masonry-bottom-title';
33024 cls += ' ' + this.cls;
33028 tag: (this.href.length) ? 'a' : 'div',
33033 cls: 'masonry-brick-split-head',
33037 cls: 'masonry-brick-paragraph',
33044 cls: 'masonry-brick-split-body',
33050 if(this.href.length){
33051 cfg.href = this.href;
33054 if(this.title.length){
33055 cfg.cn[0].cn[0].cn.push({
33057 cls: 'masonry-brick-title',
33062 if(this.html.length){
33063 cfg.cn[1].cn.push({
33065 cls: 'masonry-brick-text',
33070 if(this.bgimage.length){
33071 cfg.cn[0].cn.push({
33073 cls: 'masonry-brick-image-view',
33078 if(this.videourl.length){
33079 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33080 // youtube support only?
33081 cfg.cn[0].cn.cn.push({
33083 cls: 'masonry-brick-image-view',
33086 allowfullscreen : true
33093 initEvents: function()
33095 switch (this.size) {
33128 this.el.on('touchstart', this.onTouchStart, this);
33129 this.el.on('touchmove', this.onTouchMove, this);
33130 this.el.on('touchend', this.onTouchEnd, this);
33131 this.el.on('contextmenu', this.onContextMenu, this);
33133 this.el.on('mouseenter' ,this.enter, this);
33134 this.el.on('mouseleave', this.leave, this);
33135 this.el.on('click', this.onClick, this);
33138 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33139 this.parent().bricks.push(this);
33144 onClick: function(e, el)
33146 var time = this.endTimer - this.startTimer;
33147 // Roo.log(e.preventDefault());
33150 e.preventDefault();
33155 if(!this.preventDefault){
33159 e.preventDefault();
33161 if (this.activeClass != '') {
33162 this.selectBrick();
33165 this.fireEvent('click', this, e);
33168 enter: function(e, el)
33170 e.preventDefault();
33172 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33176 if(this.bgimage.length && this.html.length){
33177 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33181 leave: function(e, el)
33183 e.preventDefault();
33185 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33189 if(this.bgimage.length && this.html.length){
33190 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33194 onTouchStart: function(e, el)
33196 // e.preventDefault();
33198 this.touchmoved = false;
33200 if(!this.isFitContainer){
33204 if(!this.bgimage.length || !this.html.length){
33208 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33210 this.timer = new Date().getTime();
33214 onTouchMove: function(e, el)
33216 this.touchmoved = true;
33219 onContextMenu : function(e,el)
33221 e.preventDefault();
33222 e.stopPropagation();
33226 onTouchEnd: function(e, el)
33228 // e.preventDefault();
33230 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33237 if(!this.bgimage.length || !this.html.length){
33239 if(this.href.length){
33240 window.location.href = this.href;
33246 if(!this.isFitContainer){
33250 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33252 window.location.href = this.href;
33255 //selection on single brick only
33256 selectBrick : function() {
33258 if (!this.parentId) {
33262 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33263 var index = m.selectedBrick.indexOf(this.id);
33266 m.selectedBrick.splice(index,1);
33267 this.el.removeClass(this.activeClass);
33271 for(var i = 0; i < m.selectedBrick.length; i++) {
33272 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33273 b.el.removeClass(b.activeClass);
33276 m.selectedBrick = [];
33278 m.selectedBrick.push(this.id);
33279 this.el.addClass(this.activeClass);
33283 isSelected : function(){
33284 return this.el.hasClass(this.activeClass);
33289 Roo.apply(Roo.bootstrap.MasonryBrick, {
33292 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33294 * register a Masonry Brick
33295 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33298 register : function(brick)
33300 //this.groups[brick.id] = brick;
33301 this.groups.add(brick.id, brick);
33304 * fetch a masonry brick based on the masonry brick ID
33305 * @param {string} the masonry brick to add
33306 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33309 get: function(brick_id)
33311 // if (typeof(this.groups[brick_id]) == 'undefined') {
33314 // return this.groups[brick_id] ;
33316 if(this.groups.key(brick_id)) {
33317 return this.groups.key(brick_id);
33335 * @class Roo.bootstrap.Brick
33336 * @extends Roo.bootstrap.Component
33337 * Bootstrap Brick class
33340 * Create a new Brick
33341 * @param {Object} config The config object
33344 Roo.bootstrap.Brick = function(config){
33345 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33351 * When a Brick is click
33352 * @param {Roo.bootstrap.Brick} this
33353 * @param {Roo.EventObject} e
33359 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33362 * @cfg {String} title
33366 * @cfg {String} html
33370 * @cfg {String} bgimage
33374 * @cfg {String} cls
33378 * @cfg {String} href
33382 * @cfg {String} video
33386 * @cfg {Boolean} square
33390 getAutoCreate : function()
33392 var cls = 'roo-brick';
33394 if(this.href.length){
33395 cls += ' roo-brick-link';
33398 if(this.bgimage.length){
33399 cls += ' roo-brick-image';
33402 if(!this.html.length && !this.bgimage.length){
33403 cls += ' roo-brick-center-title';
33406 if(!this.html.length && this.bgimage.length){
33407 cls += ' roo-brick-bottom-title';
33411 cls += ' ' + this.cls;
33415 tag: (this.href.length) ? 'a' : 'div',
33420 cls: 'roo-brick-paragraph',
33426 if(this.href.length){
33427 cfg.href = this.href;
33430 var cn = cfg.cn[0].cn;
33432 if(this.title.length){
33435 cls: 'roo-brick-title',
33440 if(this.html.length){
33443 cls: 'roo-brick-text',
33450 if(this.bgimage.length){
33453 cls: 'roo-brick-image-view',
33461 initEvents: function()
33463 if(this.title.length || this.html.length){
33464 this.el.on('mouseenter' ,this.enter, this);
33465 this.el.on('mouseleave', this.leave, this);
33468 Roo.EventManager.onWindowResize(this.resize, this);
33470 if(this.bgimage.length){
33471 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33472 this.imageEl.on('load', this.onImageLoad, this);
33479 onImageLoad : function()
33484 resize : function()
33486 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33488 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33490 if(this.bgimage.length){
33491 var image = this.el.select('.roo-brick-image-view', true).first();
33493 image.setWidth(paragraph.getWidth());
33496 image.setHeight(paragraph.getWidth());
33499 this.el.setHeight(image.getHeight());
33500 paragraph.setHeight(image.getHeight());
33506 enter: function(e, el)
33508 e.preventDefault();
33510 if(this.bgimage.length){
33511 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33512 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33516 leave: function(e, el)
33518 e.preventDefault();
33520 if(this.bgimage.length){
33521 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33522 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33537 * @class Roo.bootstrap.NumberField
33538 * @extends Roo.bootstrap.Input
33539 * Bootstrap NumberField class
33545 * Create a new NumberField
33546 * @param {Object} config The config object
33549 Roo.bootstrap.NumberField = function(config){
33550 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33553 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33556 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33558 allowDecimals : true,
33560 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33562 decimalSeparator : ".",
33564 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33566 decimalPrecision : 2,
33568 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33570 allowNegative : true,
33573 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33577 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33579 minValue : Number.NEGATIVE_INFINITY,
33581 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33583 maxValue : Number.MAX_VALUE,
33585 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33587 minText : "The minimum value for this field is {0}",
33589 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33591 maxText : "The maximum value for this field is {0}",
33593 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33594 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33596 nanText : "{0} is not a valid number",
33598 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33600 thousandsDelimiter : false,
33602 * @cfg {String} valueAlign alignment of value
33604 valueAlign : "left",
33606 getAutoCreate : function()
33608 var hiddenInput = {
33612 cls: 'hidden-number-input'
33616 hiddenInput.name = this.name;
33621 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33623 this.name = hiddenInput.name;
33625 if(cfg.cn.length > 0) {
33626 cfg.cn.push(hiddenInput);
33633 initEvents : function()
33635 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33637 var allowed = "0123456789";
33639 if(this.allowDecimals){
33640 allowed += this.decimalSeparator;
33643 if(this.allowNegative){
33647 if(this.thousandsDelimiter) {
33651 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33653 var keyPress = function(e){
33655 var k = e.getKey();
33657 var c = e.getCharCode();
33660 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33661 allowed.indexOf(String.fromCharCode(c)) === -1
33667 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33671 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33676 this.el.on("keypress", keyPress, this);
33679 validateValue : function(value)
33682 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33686 var num = this.parseValue(value);
33689 this.markInvalid(String.format(this.nanText, value));
33693 if(num < this.minValue){
33694 this.markInvalid(String.format(this.minText, this.minValue));
33698 if(num > this.maxValue){
33699 this.markInvalid(String.format(this.maxText, this.maxValue));
33706 getValue : function()
33708 var v = this.hiddenEl().getValue();
33710 return this.fixPrecision(this.parseValue(v));
33713 parseValue : function(value)
33715 if(this.thousandsDelimiter) {
33717 r = new RegExp(",", "g");
33718 value = value.replace(r, "");
33721 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33722 return isNaN(value) ? '' : value;
33725 fixPrecision : function(value)
33727 if(this.thousandsDelimiter) {
33729 r = new RegExp(",", "g");
33730 value = value.replace(r, "");
33733 var nan = isNaN(value);
33735 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33736 return nan ? '' : value;
33738 return parseFloat(value).toFixed(this.decimalPrecision);
33741 setValue : function(v)
33743 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33749 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33751 this.inputEl().dom.value = (v == '') ? '' :
33752 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33754 if(!this.allowZero && v === '0') {
33755 this.hiddenEl().dom.value = '';
33756 this.inputEl().dom.value = '';
33763 decimalPrecisionFcn : function(v)
33765 return Math.floor(v);
33768 beforeBlur : function()
33770 var v = this.parseValue(this.getRawValue());
33772 if(v || v === 0 || v === ''){
33777 hiddenEl : function()
33779 return this.el.select('input.hidden-number-input',true).first();
33791 * @class Roo.bootstrap.DocumentSlider
33792 * @extends Roo.bootstrap.Component
33793 * Bootstrap DocumentSlider class
33796 * Create a new DocumentViewer
33797 * @param {Object} config The config object
33800 Roo.bootstrap.DocumentSlider = function(config){
33801 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33808 * Fire after initEvent
33809 * @param {Roo.bootstrap.DocumentSlider} this
33814 * Fire after update
33815 * @param {Roo.bootstrap.DocumentSlider} this
33821 * @param {Roo.bootstrap.DocumentSlider} this
33827 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33833 getAutoCreate : function()
33837 cls : 'roo-document-slider',
33841 cls : 'roo-document-slider-header',
33845 cls : 'roo-document-slider-header-title'
33851 cls : 'roo-document-slider-body',
33855 cls : 'roo-document-slider-prev',
33859 cls : 'fa fa-chevron-left'
33865 cls : 'roo-document-slider-thumb',
33869 cls : 'roo-document-slider-image'
33875 cls : 'roo-document-slider-next',
33879 cls : 'fa fa-chevron-right'
33891 initEvents : function()
33893 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33894 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33896 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33897 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33899 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33900 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33902 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33903 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33905 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33906 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33908 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33909 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33911 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33912 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33914 this.thumbEl.on('click', this.onClick, this);
33916 this.prevIndicator.on('click', this.prev, this);
33918 this.nextIndicator.on('click', this.next, this);
33922 initial : function()
33924 if(this.files.length){
33925 this.indicator = 1;
33929 this.fireEvent('initial', this);
33932 update : function()
33934 this.imageEl.attr('src', this.files[this.indicator - 1]);
33936 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33938 this.prevIndicator.show();
33940 if(this.indicator == 1){
33941 this.prevIndicator.hide();
33944 this.nextIndicator.show();
33946 if(this.indicator == this.files.length){
33947 this.nextIndicator.hide();
33950 this.thumbEl.scrollTo('top');
33952 this.fireEvent('update', this);
33955 onClick : function(e)
33957 e.preventDefault();
33959 this.fireEvent('click', this);
33964 e.preventDefault();
33966 this.indicator = Math.max(1, this.indicator - 1);
33973 e.preventDefault();
33975 this.indicator = Math.min(this.files.length, this.indicator + 1);
33989 * @class Roo.bootstrap.RadioSet
33990 * @extends Roo.bootstrap.Input
33991 * Bootstrap RadioSet class
33992 * @cfg {String} indicatorpos (left|right) default left
33993 * @cfg {Boolean} inline (true|false) inline the element (default true)
33994 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33996 * Create a new RadioSet
33997 * @param {Object} config The config object
34000 Roo.bootstrap.RadioSet = function(config){
34002 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34006 Roo.bootstrap.RadioSet.register(this);
34011 * Fires when the element is checked or unchecked.
34012 * @param {Roo.bootstrap.RadioSet} this This radio
34013 * @param {Roo.bootstrap.Radio} item The checked item
34018 * Fires when the element is click.
34019 * @param {Roo.bootstrap.RadioSet} this This radio set
34020 * @param {Roo.bootstrap.Radio} item The checked item
34021 * @param {Roo.EventObject} e The event object
34028 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34036 indicatorpos : 'left',
34038 getAutoCreate : function()
34042 cls : 'roo-radio-set-label',
34046 html : this.fieldLabel
34051 if(this.indicatorpos == 'left'){
34054 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34055 tooltip : 'This field is required'
34060 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34061 tooltip : 'This field is required'
34067 cls : 'roo-radio-set-items'
34070 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34072 if (align === 'left' && this.fieldLabel.length) {
34075 cls : "roo-radio-set-right",
34081 if(this.labelWidth > 12){
34082 label.style = "width: " + this.labelWidth + 'px';
34085 if(this.labelWidth < 13 && this.labelmd == 0){
34086 this.labelmd = this.labelWidth;
34089 if(this.labellg > 0){
34090 label.cls += ' col-lg-' + this.labellg;
34091 items.cls += ' col-lg-' + (12 - this.labellg);
34094 if(this.labelmd > 0){
34095 label.cls += ' col-md-' + this.labelmd;
34096 items.cls += ' col-md-' + (12 - this.labelmd);
34099 if(this.labelsm > 0){
34100 label.cls += ' col-sm-' + this.labelsm;
34101 items.cls += ' col-sm-' + (12 - this.labelsm);
34104 if(this.labelxs > 0){
34105 label.cls += ' col-xs-' + this.labelxs;
34106 items.cls += ' col-xs-' + (12 - this.labelxs);
34112 cls : 'roo-radio-set',
34116 cls : 'roo-radio-set-input',
34119 value : this.value ? this.value : ''
34126 if(this.weight.length){
34127 cfg.cls += ' roo-radio-' + this.weight;
34131 cfg.cls += ' roo-radio-set-inline';
34135 ['xs','sm','md','lg'].map(function(size){
34136 if (settings[size]) {
34137 cfg.cls += ' col-' + size + '-' + settings[size];
34145 initEvents : function()
34147 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34148 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34150 if(!this.fieldLabel.length){
34151 this.labelEl.hide();
34154 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34155 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34157 this.indicator = this.indicatorEl();
34159 if(this.indicator){
34160 this.indicator.addClass('invisible');
34163 this.originalValue = this.getValue();
34167 inputEl: function ()
34169 return this.el.select('.roo-radio-set-input', true).first();
34172 getChildContainer : function()
34174 return this.itemsEl;
34177 register : function(item)
34179 this.radioes.push(item);
34183 validate : function()
34185 if(this.getVisibilityEl().hasClass('hidden')){
34191 Roo.each(this.radioes, function(i){
34200 if(this.allowBlank) {
34204 if(this.disabled || valid){
34209 this.markInvalid();
34214 markValid : function()
34216 if(this.labelEl.isVisible(true)){
34217 this.indicatorEl().removeClass('visible');
34218 this.indicatorEl().addClass('invisible');
34221 this.el.removeClass([this.invalidClass, this.validClass]);
34222 this.el.addClass(this.validClass);
34224 this.fireEvent('valid', this);
34227 markInvalid : function(msg)
34229 if(this.allowBlank || this.disabled){
34233 if(this.labelEl.isVisible(true)){
34234 this.indicatorEl().removeClass('invisible');
34235 this.indicatorEl().addClass('visible');
34238 this.el.removeClass([this.invalidClass, this.validClass]);
34239 this.el.addClass(this.invalidClass);
34241 this.fireEvent('invalid', this, msg);
34245 setValue : function(v, suppressEvent)
34247 if(this.value === v){
34254 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34257 Roo.each(this.radioes, function(i){
34259 i.el.removeClass('checked');
34262 Roo.each(this.radioes, function(i){
34264 if(i.value === v || i.value.toString() === v.toString()){
34266 i.el.addClass('checked');
34268 if(suppressEvent !== true){
34269 this.fireEvent('check', this, i);
34280 clearInvalid : function(){
34282 if(!this.el || this.preventMark){
34286 this.el.removeClass([this.invalidClass]);
34288 this.fireEvent('valid', this);
34293 Roo.apply(Roo.bootstrap.RadioSet, {
34297 register : function(set)
34299 this.groups[set.name] = set;
34302 get: function(name)
34304 if (typeof(this.groups[name]) == 'undefined') {
34308 return this.groups[name] ;
34314 * Ext JS Library 1.1.1
34315 * Copyright(c) 2006-2007, Ext JS, LLC.
34317 * Originally Released Under LGPL - original licence link has changed is not relivant.
34320 * <script type="text/javascript">
34325 * @class Roo.bootstrap.SplitBar
34326 * @extends Roo.util.Observable
34327 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34331 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34332 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34333 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34334 split.minSize = 100;
34335 split.maxSize = 600;
34336 split.animate = true;
34337 split.on('moved', splitterMoved);
34340 * Create a new SplitBar
34341 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34342 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34343 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34344 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34345 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34346 position of the SplitBar).
34348 Roo.bootstrap.SplitBar = function(cfg){
34353 // dragElement : elm
34354 // resizingElement: el,
34356 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34357 // placement : Roo.bootstrap.SplitBar.LEFT ,
34358 // existingProxy ???
34361 this.el = Roo.get(cfg.dragElement, true);
34362 this.el.dom.unselectable = "on";
34364 this.resizingEl = Roo.get(cfg.resizingElement, true);
34368 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34369 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34372 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34375 * The minimum size of the resizing element. (Defaults to 0)
34381 * The maximum size of the resizing element. (Defaults to 2000)
34384 this.maxSize = 2000;
34387 * Whether to animate the transition to the new size
34390 this.animate = false;
34393 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34396 this.useShim = false;
34401 if(!cfg.existingProxy){
34403 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34405 this.proxy = Roo.get(cfg.existingProxy).dom;
34408 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34411 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34414 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34417 this.dragSpecs = {};
34420 * @private The adapter to use to positon and resize elements
34422 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34423 this.adapter.init(this);
34425 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34427 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34428 this.el.addClass("roo-splitbar-h");
34431 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34432 this.el.addClass("roo-splitbar-v");
34438 * Fires when the splitter is moved (alias for {@link #event-moved})
34439 * @param {Roo.bootstrap.SplitBar} this
34440 * @param {Number} newSize the new width or height
34445 * Fires when the splitter is moved
34446 * @param {Roo.bootstrap.SplitBar} this
34447 * @param {Number} newSize the new width or height
34451 * @event beforeresize
34452 * Fires before the splitter is dragged
34453 * @param {Roo.bootstrap.SplitBar} this
34455 "beforeresize" : true,
34457 "beforeapply" : true
34460 Roo.util.Observable.call(this);
34463 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34464 onStartProxyDrag : function(x, y){
34465 this.fireEvent("beforeresize", this);
34467 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34469 o.enableDisplayMode("block");
34470 // all splitbars share the same overlay
34471 Roo.bootstrap.SplitBar.prototype.overlay = o;
34473 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34474 this.overlay.show();
34475 Roo.get(this.proxy).setDisplayed("block");
34476 var size = this.adapter.getElementSize(this);
34477 this.activeMinSize = this.getMinimumSize();;
34478 this.activeMaxSize = this.getMaximumSize();;
34479 var c1 = size - this.activeMinSize;
34480 var c2 = Math.max(this.activeMaxSize - size, 0);
34481 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34482 this.dd.resetConstraints();
34483 this.dd.setXConstraint(
34484 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34485 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34487 this.dd.setYConstraint(0, 0);
34489 this.dd.resetConstraints();
34490 this.dd.setXConstraint(0, 0);
34491 this.dd.setYConstraint(
34492 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34493 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34496 this.dragSpecs.startSize = size;
34497 this.dragSpecs.startPoint = [x, y];
34498 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34502 * @private Called after the drag operation by the DDProxy
34504 onEndProxyDrag : function(e){
34505 Roo.get(this.proxy).setDisplayed(false);
34506 var endPoint = Roo.lib.Event.getXY(e);
34508 this.overlay.hide();
34511 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34512 newSize = this.dragSpecs.startSize +
34513 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34514 endPoint[0] - this.dragSpecs.startPoint[0] :
34515 this.dragSpecs.startPoint[0] - endPoint[0]
34518 newSize = this.dragSpecs.startSize +
34519 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34520 endPoint[1] - this.dragSpecs.startPoint[1] :
34521 this.dragSpecs.startPoint[1] - endPoint[1]
34524 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34525 if(newSize != this.dragSpecs.startSize){
34526 if(this.fireEvent('beforeapply', this, newSize) !== false){
34527 this.adapter.setElementSize(this, newSize);
34528 this.fireEvent("moved", this, newSize);
34529 this.fireEvent("resize", this, newSize);
34535 * Get the adapter this SplitBar uses
34536 * @return The adapter object
34538 getAdapter : function(){
34539 return this.adapter;
34543 * Set the adapter this SplitBar uses
34544 * @param {Object} adapter A SplitBar adapter object
34546 setAdapter : function(adapter){
34547 this.adapter = adapter;
34548 this.adapter.init(this);
34552 * Gets the minimum size for the resizing element
34553 * @return {Number} The minimum size
34555 getMinimumSize : function(){
34556 return this.minSize;
34560 * Sets the minimum size for the resizing element
34561 * @param {Number} minSize The minimum size
34563 setMinimumSize : function(minSize){
34564 this.minSize = minSize;
34568 * Gets the maximum size for the resizing element
34569 * @return {Number} The maximum size
34571 getMaximumSize : function(){
34572 return this.maxSize;
34576 * Sets the maximum size for the resizing element
34577 * @param {Number} maxSize The maximum size
34579 setMaximumSize : function(maxSize){
34580 this.maxSize = maxSize;
34584 * Sets the initialize size for the resizing element
34585 * @param {Number} size The initial size
34587 setCurrentSize : function(size){
34588 var oldAnimate = this.animate;
34589 this.animate = false;
34590 this.adapter.setElementSize(this, size);
34591 this.animate = oldAnimate;
34595 * Destroy this splitbar.
34596 * @param {Boolean} removeEl True to remove the element
34598 destroy : function(removeEl){
34600 this.shim.remove();
34603 this.proxy.parentNode.removeChild(this.proxy);
34611 * @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.
34613 Roo.bootstrap.SplitBar.createProxy = function(dir){
34614 var proxy = new Roo.Element(document.createElement("div"));
34615 proxy.unselectable();
34616 var cls = 'roo-splitbar-proxy';
34617 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34618 document.body.appendChild(proxy.dom);
34623 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34624 * Default Adapter. It assumes the splitter and resizing element are not positioned
34625 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34627 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34630 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34631 // do nothing for now
34632 init : function(s){
34636 * Called before drag operations to get the current size of the resizing element.
34637 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34639 getElementSize : function(s){
34640 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34641 return s.resizingEl.getWidth();
34643 return s.resizingEl.getHeight();
34648 * Called after drag operations to set the size of the resizing element.
34649 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34650 * @param {Number} newSize The new size to set
34651 * @param {Function} onComplete A function to be invoked when resizing is complete
34653 setElementSize : function(s, newSize, onComplete){
34654 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34656 s.resizingEl.setWidth(newSize);
34658 onComplete(s, newSize);
34661 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34666 s.resizingEl.setHeight(newSize);
34668 onComplete(s, newSize);
34671 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34678 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34679 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34680 * Adapter that moves the splitter element to align with the resized sizing element.
34681 * Used with an absolute positioned SplitBar.
34682 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34683 * document.body, make sure you assign an id to the body element.
34685 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34686 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34687 this.container = Roo.get(container);
34690 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34691 init : function(s){
34692 this.basic.init(s);
34695 getElementSize : function(s){
34696 return this.basic.getElementSize(s);
34699 setElementSize : function(s, newSize, onComplete){
34700 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34703 moveSplitter : function(s){
34704 var yes = Roo.bootstrap.SplitBar;
34705 switch(s.placement){
34707 s.el.setX(s.resizingEl.getRight());
34710 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34713 s.el.setY(s.resizingEl.getBottom());
34716 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34723 * Orientation constant - Create a vertical SplitBar
34727 Roo.bootstrap.SplitBar.VERTICAL = 1;
34730 * Orientation constant - Create a horizontal SplitBar
34734 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34737 * Placement constant - The resizing element is to the left of the splitter element
34741 Roo.bootstrap.SplitBar.LEFT = 1;
34744 * Placement constant - The resizing element is to the right of the splitter element
34748 Roo.bootstrap.SplitBar.RIGHT = 2;
34751 * Placement constant - The resizing element is positioned above the splitter element
34755 Roo.bootstrap.SplitBar.TOP = 3;
34758 * Placement constant - The resizing element is positioned under splitter element
34762 Roo.bootstrap.SplitBar.BOTTOM = 4;
34763 Roo.namespace("Roo.bootstrap.layout");/*
34765 * Ext JS Library 1.1.1
34766 * Copyright(c) 2006-2007, Ext JS, LLC.
34768 * Originally Released Under LGPL - original licence link has changed is not relivant.
34771 * <script type="text/javascript">
34775 * @class Roo.bootstrap.layout.Manager
34776 * @extends Roo.bootstrap.Component
34777 * Base class for layout managers.
34779 Roo.bootstrap.layout.Manager = function(config)
34781 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34787 /** false to disable window resize monitoring @type Boolean */
34788 this.monitorWindowResize = true;
34793 * Fires when a layout is performed.
34794 * @param {Roo.LayoutManager} this
34798 * @event regionresized
34799 * Fires when the user resizes a region.
34800 * @param {Roo.LayoutRegion} region The resized region
34801 * @param {Number} newSize The new size (width for east/west, height for north/south)
34803 "regionresized" : true,
34805 * @event regioncollapsed
34806 * Fires when a region is collapsed.
34807 * @param {Roo.LayoutRegion} region The collapsed region
34809 "regioncollapsed" : true,
34811 * @event regionexpanded
34812 * Fires when a region is expanded.
34813 * @param {Roo.LayoutRegion} region The expanded region
34815 "regionexpanded" : true
34817 this.updating = false;
34820 this.el = Roo.get(config.el);
34826 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34831 monitorWindowResize : true,
34837 onRender : function(ct, position)
34840 this.el = Roo.get(ct);
34843 //this.fireEvent('render',this);
34847 initEvents: function()
34851 // ie scrollbar fix
34852 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34853 document.body.scroll = "no";
34854 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34855 this.el.position('relative');
34857 this.id = this.el.id;
34858 this.el.addClass("roo-layout-container");
34859 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34860 if(this.el.dom != document.body ) {
34861 this.el.on('resize', this.layout,this);
34862 this.el.on('show', this.layout,this);
34868 * Returns true if this layout is currently being updated
34869 * @return {Boolean}
34871 isUpdating : function(){
34872 return this.updating;
34876 * Suspend the LayoutManager from doing auto-layouts while
34877 * making multiple add or remove calls
34879 beginUpdate : function(){
34880 this.updating = true;
34884 * Restore auto-layouts and optionally disable the manager from performing a layout
34885 * @param {Boolean} noLayout true to disable a layout update
34887 endUpdate : function(noLayout){
34888 this.updating = false;
34894 layout: function(){
34898 onRegionResized : function(region, newSize){
34899 this.fireEvent("regionresized", region, newSize);
34903 onRegionCollapsed : function(region){
34904 this.fireEvent("regioncollapsed", region);
34907 onRegionExpanded : function(region){
34908 this.fireEvent("regionexpanded", region);
34912 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34913 * performs box-model adjustments.
34914 * @return {Object} The size as an object {width: (the width), height: (the height)}
34916 getViewSize : function()
34919 if(this.el.dom != document.body){
34920 size = this.el.getSize();
34922 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34924 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34925 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34930 * Returns the Element this layout is bound to.
34931 * @return {Roo.Element}
34933 getEl : function(){
34938 * Returns the specified region.
34939 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34940 * @return {Roo.LayoutRegion}
34942 getRegion : function(target){
34943 return this.regions[target.toLowerCase()];
34946 onWindowResize : function(){
34947 if(this.monitorWindowResize){
34954 * Ext JS Library 1.1.1
34955 * Copyright(c) 2006-2007, Ext JS, LLC.
34957 * Originally Released Under LGPL - original licence link has changed is not relivant.
34960 * <script type="text/javascript">
34963 * @class Roo.bootstrap.layout.Border
34964 * @extends Roo.bootstrap.layout.Manager
34965 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34966 * please see: examples/bootstrap/nested.html<br><br>
34968 <b>The container the layout is rendered into can be either the body element or any other element.
34969 If it is not the body element, the container needs to either be an absolute positioned element,
34970 or you will need to add "position:relative" to the css of the container. You will also need to specify
34971 the container size if it is not the body element.</b>
34974 * Create a new Border
34975 * @param {Object} config Configuration options
34977 Roo.bootstrap.layout.Border = function(config){
34978 config = config || {};
34979 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34983 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34984 if(config[region]){
34985 config[region].region = region;
34986 this.addRegion(config[region]);
34992 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34994 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34996 * Creates and adds a new region if it doesn't already exist.
34997 * @param {String} target The target region key (north, south, east, west or center).
34998 * @param {Object} config The regions config object
34999 * @return {BorderLayoutRegion} The new region
35001 addRegion : function(config)
35003 if(!this.regions[config.region]){
35004 var r = this.factory(config);
35005 this.bindRegion(r);
35007 return this.regions[config.region];
35011 bindRegion : function(r){
35012 this.regions[r.config.region] = r;
35014 r.on("visibilitychange", this.layout, this);
35015 r.on("paneladded", this.layout, this);
35016 r.on("panelremoved", this.layout, this);
35017 r.on("invalidated", this.layout, this);
35018 r.on("resized", this.onRegionResized, this);
35019 r.on("collapsed", this.onRegionCollapsed, this);
35020 r.on("expanded", this.onRegionExpanded, this);
35024 * Performs a layout update.
35026 layout : function()
35028 if(this.updating) {
35032 // render all the rebions if they have not been done alreayd?
35033 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35034 if(this.regions[region] && !this.regions[region].bodyEl){
35035 this.regions[region].onRender(this.el)
35039 var size = this.getViewSize();
35040 var w = size.width;
35041 var h = size.height;
35046 //var x = 0, y = 0;
35048 var rs = this.regions;
35049 var north = rs["north"];
35050 var south = rs["south"];
35051 var west = rs["west"];
35052 var east = rs["east"];
35053 var center = rs["center"];
35054 //if(this.hideOnLayout){ // not supported anymore
35055 //c.el.setStyle("display", "none");
35057 if(north && north.isVisible()){
35058 var b = north.getBox();
35059 var m = north.getMargins();
35060 b.width = w - (m.left+m.right);
35063 centerY = b.height + b.y + m.bottom;
35064 centerH -= centerY;
35065 north.updateBox(this.safeBox(b));
35067 if(south && south.isVisible()){
35068 var b = south.getBox();
35069 var m = south.getMargins();
35070 b.width = w - (m.left+m.right);
35072 var totalHeight = (b.height + m.top + m.bottom);
35073 b.y = h - totalHeight + m.top;
35074 centerH -= totalHeight;
35075 south.updateBox(this.safeBox(b));
35077 if(west && west.isVisible()){
35078 var b = west.getBox();
35079 var m = west.getMargins();
35080 b.height = centerH - (m.top+m.bottom);
35082 b.y = centerY + m.top;
35083 var totalWidth = (b.width + m.left + m.right);
35084 centerX += totalWidth;
35085 centerW -= totalWidth;
35086 west.updateBox(this.safeBox(b));
35088 if(east && east.isVisible()){
35089 var b = east.getBox();
35090 var m = east.getMargins();
35091 b.height = centerH - (m.top+m.bottom);
35092 var totalWidth = (b.width + m.left + m.right);
35093 b.x = w - totalWidth + m.left;
35094 b.y = centerY + m.top;
35095 centerW -= totalWidth;
35096 east.updateBox(this.safeBox(b));
35099 var m = center.getMargins();
35101 x: centerX + m.left,
35102 y: centerY + m.top,
35103 width: centerW - (m.left+m.right),
35104 height: centerH - (m.top+m.bottom)
35106 //if(this.hideOnLayout){
35107 //center.el.setStyle("display", "block");
35109 center.updateBox(this.safeBox(centerBox));
35112 this.fireEvent("layout", this);
35116 safeBox : function(box){
35117 box.width = Math.max(0, box.width);
35118 box.height = Math.max(0, box.height);
35123 * Adds a ContentPanel (or subclass) to this layout.
35124 * @param {String} target The target region key (north, south, east, west or center).
35125 * @param {Roo.ContentPanel} panel The panel to add
35126 * @return {Roo.ContentPanel} The added panel
35128 add : function(target, panel){
35130 target = target.toLowerCase();
35131 return this.regions[target].add(panel);
35135 * Remove a ContentPanel (or subclass) to this layout.
35136 * @param {String} target The target region key (north, south, east, west or center).
35137 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35138 * @return {Roo.ContentPanel} The removed panel
35140 remove : function(target, panel){
35141 target = target.toLowerCase();
35142 return this.regions[target].remove(panel);
35146 * Searches all regions for a panel with the specified id
35147 * @param {String} panelId
35148 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35150 findPanel : function(panelId){
35151 var rs = this.regions;
35152 for(var target in rs){
35153 if(typeof rs[target] != "function"){
35154 var p = rs[target].getPanel(panelId);
35164 * Searches all regions for a panel with the specified id and activates (shows) it.
35165 * @param {String/ContentPanel} panelId The panels id or the panel itself
35166 * @return {Roo.ContentPanel} The shown panel or null
35168 showPanel : function(panelId) {
35169 var rs = this.regions;
35170 for(var target in rs){
35171 var r = rs[target];
35172 if(typeof r != "function"){
35173 if(r.hasPanel(panelId)){
35174 return r.showPanel(panelId);
35182 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35183 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35186 restoreState : function(provider){
35188 provider = Roo.state.Manager;
35190 var sm = new Roo.LayoutStateManager();
35191 sm.init(this, provider);
35197 * Adds a xtype elements to the layout.
35201 xtype : 'ContentPanel',
35208 xtype : 'NestedLayoutPanel',
35214 items : [ ... list of content panels or nested layout panels.. ]
35218 * @param {Object} cfg Xtype definition of item to add.
35220 addxtype : function(cfg)
35222 // basically accepts a pannel...
35223 // can accept a layout region..!?!?
35224 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35227 // theory? children can only be panels??
35229 //if (!cfg.xtype.match(/Panel$/)) {
35234 if (typeof(cfg.region) == 'undefined') {
35235 Roo.log("Failed to add Panel, region was not set");
35239 var region = cfg.region;
35245 xitems = cfg.items;
35252 case 'Content': // ContentPanel (el, cfg)
35253 case 'Scroll': // ContentPanel (el, cfg)
35255 cfg.autoCreate = true;
35256 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35258 // var el = this.el.createChild();
35259 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35262 this.add(region, ret);
35266 case 'TreePanel': // our new panel!
35267 cfg.el = this.el.createChild();
35268 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35269 this.add(region, ret);
35274 // create a new Layout (which is a Border Layout...
35276 var clayout = cfg.layout;
35277 clayout.el = this.el.createChild();
35278 clayout.items = clayout.items || [];
35282 // replace this exitems with the clayout ones..
35283 xitems = clayout.items;
35285 // force background off if it's in center...
35286 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35287 cfg.background = false;
35289 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35292 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35293 //console.log('adding nested layout panel ' + cfg.toSource());
35294 this.add(region, ret);
35295 nb = {}; /// find first...
35300 // needs grid and region
35302 //var el = this.getRegion(region).el.createChild();
35304 *var el = this.el.createChild();
35305 // create the grid first...
35306 cfg.grid.container = el;
35307 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35310 if (region == 'center' && this.active ) {
35311 cfg.background = false;
35314 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35316 this.add(region, ret);
35318 if (cfg.background) {
35319 // render grid on panel activation (if panel background)
35320 ret.on('activate', function(gp) {
35321 if (!gp.grid.rendered) {
35322 // gp.grid.render(el);
35326 // cfg.grid.render(el);
35332 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35333 // it was the old xcomponent building that caused this before.
35334 // espeically if border is the top element in the tree.
35344 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35346 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35347 this.add(region, ret);
35351 throw "Can not add '" + cfg.xtype + "' to Border";
35357 this.beginUpdate();
35361 Roo.each(xitems, function(i) {
35362 region = nb && i.region ? i.region : false;
35364 var add = ret.addxtype(i);
35367 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35368 if (!i.background) {
35369 abn[region] = nb[region] ;
35376 // make the last non-background panel active..
35377 //if (nb) { Roo.log(abn); }
35380 for(var r in abn) {
35381 region = this.getRegion(r);
35383 // tried using nb[r], but it does not work..
35385 region.showPanel(abn[r]);
35396 factory : function(cfg)
35399 var validRegions = Roo.bootstrap.layout.Border.regions;
35401 var target = cfg.region;
35404 var r = Roo.bootstrap.layout;
35408 return new r.North(cfg);
35410 return new r.South(cfg);
35412 return new r.East(cfg);
35414 return new r.West(cfg);
35416 return new r.Center(cfg);
35418 throw 'Layout region "'+target+'" not supported.';
35425 * Ext JS Library 1.1.1
35426 * Copyright(c) 2006-2007, Ext JS, LLC.
35428 * Originally Released Under LGPL - original licence link has changed is not relivant.
35431 * <script type="text/javascript">
35435 * @class Roo.bootstrap.layout.Basic
35436 * @extends Roo.util.Observable
35437 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35438 * and does not have a titlebar, tabs or any other features. All it does is size and position
35439 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35440 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35441 * @cfg {string} region the region that it inhabits..
35442 * @cfg {bool} skipConfig skip config?
35446 Roo.bootstrap.layout.Basic = function(config){
35448 this.mgr = config.mgr;
35450 this.position = config.region;
35452 var skipConfig = config.skipConfig;
35456 * @scope Roo.BasicLayoutRegion
35460 * @event beforeremove
35461 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35462 * @param {Roo.LayoutRegion} this
35463 * @param {Roo.ContentPanel} panel The panel
35464 * @param {Object} e The cancel event object
35466 "beforeremove" : true,
35468 * @event invalidated
35469 * Fires when the layout for this region is changed.
35470 * @param {Roo.LayoutRegion} this
35472 "invalidated" : true,
35474 * @event visibilitychange
35475 * Fires when this region is shown or hidden
35476 * @param {Roo.LayoutRegion} this
35477 * @param {Boolean} visibility true or false
35479 "visibilitychange" : true,
35481 * @event paneladded
35482 * Fires when a panel is added.
35483 * @param {Roo.LayoutRegion} this
35484 * @param {Roo.ContentPanel} panel The panel
35486 "paneladded" : true,
35488 * @event panelremoved
35489 * Fires when a panel is removed.
35490 * @param {Roo.LayoutRegion} this
35491 * @param {Roo.ContentPanel} panel The panel
35493 "panelremoved" : true,
35495 * @event beforecollapse
35496 * Fires when this region before collapse.
35497 * @param {Roo.LayoutRegion} this
35499 "beforecollapse" : true,
35502 * Fires when this region is collapsed.
35503 * @param {Roo.LayoutRegion} this
35505 "collapsed" : true,
35508 * Fires when this region is expanded.
35509 * @param {Roo.LayoutRegion} this
35514 * Fires when this region is slid into view.
35515 * @param {Roo.LayoutRegion} this
35517 "slideshow" : true,
35520 * Fires when this region slides out of view.
35521 * @param {Roo.LayoutRegion} this
35523 "slidehide" : true,
35525 * @event panelactivated
35526 * Fires when a panel is activated.
35527 * @param {Roo.LayoutRegion} this
35528 * @param {Roo.ContentPanel} panel The activated panel
35530 "panelactivated" : true,
35533 * Fires when the user resizes this region.
35534 * @param {Roo.LayoutRegion} this
35535 * @param {Number} newSize The new size (width for east/west, height for north/south)
35539 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35540 this.panels = new Roo.util.MixedCollection();
35541 this.panels.getKey = this.getPanelId.createDelegate(this);
35543 this.activePanel = null;
35544 // ensure listeners are added...
35546 if (config.listeners || config.events) {
35547 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35548 listeners : config.listeners || {},
35549 events : config.events || {}
35553 if(skipConfig !== true){
35554 this.applyConfig(config);
35558 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35560 getPanelId : function(p){
35564 applyConfig : function(config){
35565 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35566 this.config = config;
35571 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35572 * the width, for horizontal (north, south) the height.
35573 * @param {Number} newSize The new width or height
35575 resizeTo : function(newSize){
35576 var el = this.el ? this.el :
35577 (this.activePanel ? this.activePanel.getEl() : null);
35579 switch(this.position){
35582 el.setWidth(newSize);
35583 this.fireEvent("resized", this, newSize);
35587 el.setHeight(newSize);
35588 this.fireEvent("resized", this, newSize);
35594 getBox : function(){
35595 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35598 getMargins : function(){
35599 return this.margins;
35602 updateBox : function(box){
35604 var el = this.activePanel.getEl();
35605 el.dom.style.left = box.x + "px";
35606 el.dom.style.top = box.y + "px";
35607 this.activePanel.setSize(box.width, box.height);
35611 * Returns the container element for this region.
35612 * @return {Roo.Element}
35614 getEl : function(){
35615 return this.activePanel;
35619 * Returns true if this region is currently visible.
35620 * @return {Boolean}
35622 isVisible : function(){
35623 return this.activePanel ? true : false;
35626 setActivePanel : function(panel){
35627 panel = this.getPanel(panel);
35628 if(this.activePanel && this.activePanel != panel){
35629 this.activePanel.setActiveState(false);
35630 this.activePanel.getEl().setLeftTop(-10000,-10000);
35632 this.activePanel = panel;
35633 panel.setActiveState(true);
35635 panel.setSize(this.box.width, this.box.height);
35637 this.fireEvent("panelactivated", this, panel);
35638 this.fireEvent("invalidated");
35642 * Show the specified panel.
35643 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35644 * @return {Roo.ContentPanel} The shown panel or null
35646 showPanel : function(panel){
35647 panel = this.getPanel(panel);
35649 this.setActivePanel(panel);
35655 * Get the active panel for this region.
35656 * @return {Roo.ContentPanel} The active panel or null
35658 getActivePanel : function(){
35659 return this.activePanel;
35663 * Add the passed ContentPanel(s)
35664 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35665 * @return {Roo.ContentPanel} The panel added (if only one was added)
35667 add : function(panel){
35668 if(arguments.length > 1){
35669 for(var i = 0, len = arguments.length; i < len; i++) {
35670 this.add(arguments[i]);
35674 if(this.hasPanel(panel)){
35675 this.showPanel(panel);
35678 var el = panel.getEl();
35679 if(el.dom.parentNode != this.mgr.el.dom){
35680 this.mgr.el.dom.appendChild(el.dom);
35682 if(panel.setRegion){
35683 panel.setRegion(this);
35685 this.panels.add(panel);
35686 el.setStyle("position", "absolute");
35687 if(!panel.background){
35688 this.setActivePanel(panel);
35689 if(this.config.initialSize && this.panels.getCount()==1){
35690 this.resizeTo(this.config.initialSize);
35693 this.fireEvent("paneladded", this, panel);
35698 * Returns true if the panel is in this region.
35699 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35700 * @return {Boolean}
35702 hasPanel : function(panel){
35703 if(typeof panel == "object"){ // must be panel obj
35704 panel = panel.getId();
35706 return this.getPanel(panel) ? true : false;
35710 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35711 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35712 * @param {Boolean} preservePanel Overrides the config preservePanel option
35713 * @return {Roo.ContentPanel} The panel that was removed
35715 remove : function(panel, preservePanel){
35716 panel = this.getPanel(panel);
35721 this.fireEvent("beforeremove", this, panel, e);
35722 if(e.cancel === true){
35725 var panelId = panel.getId();
35726 this.panels.removeKey(panelId);
35731 * Returns the panel specified or null if it's not in this region.
35732 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35733 * @return {Roo.ContentPanel}
35735 getPanel : function(id){
35736 if(typeof id == "object"){ // must be panel obj
35739 return this.panels.get(id);
35743 * Returns this regions position (north/south/east/west/center).
35746 getPosition: function(){
35747 return this.position;
35751 * Ext JS Library 1.1.1
35752 * Copyright(c) 2006-2007, Ext JS, LLC.
35754 * Originally Released Under LGPL - original licence link has changed is not relivant.
35757 * <script type="text/javascript">
35761 * @class Roo.bootstrap.layout.Region
35762 * @extends Roo.bootstrap.layout.Basic
35763 * This class represents a region in a layout manager.
35765 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35766 * @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})
35767 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35768 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35769 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35770 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35771 * @cfg {String} title The title for the region (overrides panel titles)
35772 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35773 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35774 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35775 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35776 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35777 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35778 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35779 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35780 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35781 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35783 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35784 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35785 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35786 * @cfg {Number} width For East/West panels
35787 * @cfg {Number} height For North/South panels
35788 * @cfg {Boolean} split To show the splitter
35789 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35791 * @cfg {string} cls Extra CSS classes to add to region
35793 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35794 * @cfg {string} region the region that it inhabits..
35797 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35798 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35800 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35801 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35802 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35804 Roo.bootstrap.layout.Region = function(config)
35806 this.applyConfig(config);
35808 var mgr = config.mgr;
35809 var pos = config.region;
35810 config.skipConfig = true;
35811 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35814 this.onRender(mgr.el);
35817 this.visible = true;
35818 this.collapsed = false;
35819 this.unrendered_panels = [];
35822 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35824 position: '', // set by wrapper (eg. north/south etc..)
35825 unrendered_panels : null, // unrendered panels.
35826 createBody : function(){
35827 /** This region's body element
35828 * @type Roo.Element */
35829 this.bodyEl = this.el.createChild({
35831 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35835 onRender: function(ctr, pos)
35837 var dh = Roo.DomHelper;
35838 /** This region's container element
35839 * @type Roo.Element */
35840 this.el = dh.append(ctr.dom, {
35842 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35844 /** This region's title element
35845 * @type Roo.Element */
35847 this.titleEl = dh.append(this.el.dom,
35850 unselectable: "on",
35851 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35853 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35854 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35857 this.titleEl.enableDisplayMode();
35858 /** This region's title text element
35859 * @type HTMLElement */
35860 this.titleTextEl = this.titleEl.dom.firstChild;
35861 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35863 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35864 this.closeBtn.enableDisplayMode();
35865 this.closeBtn.on("click", this.closeClicked, this);
35866 this.closeBtn.hide();
35868 this.createBody(this.config);
35869 if(this.config.hideWhenEmpty){
35871 this.on("paneladded", this.validateVisibility, this);
35872 this.on("panelremoved", this.validateVisibility, this);
35874 if(this.autoScroll){
35875 this.bodyEl.setStyle("overflow", "auto");
35877 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35879 //if(c.titlebar !== false){
35880 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35881 this.titleEl.hide();
35883 this.titleEl.show();
35884 if(this.config.title){
35885 this.titleTextEl.innerHTML = this.config.title;
35889 if(this.config.collapsed){
35890 this.collapse(true);
35892 if(this.config.hidden){
35896 if (this.unrendered_panels && this.unrendered_panels.length) {
35897 for (var i =0;i< this.unrendered_panels.length; i++) {
35898 this.add(this.unrendered_panels[i]);
35900 this.unrendered_panels = null;
35906 applyConfig : function(c)
35909 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35910 var dh = Roo.DomHelper;
35911 if(c.titlebar !== false){
35912 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35913 this.collapseBtn.on("click", this.collapse, this);
35914 this.collapseBtn.enableDisplayMode();
35916 if(c.showPin === true || this.showPin){
35917 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35918 this.stickBtn.enableDisplayMode();
35919 this.stickBtn.on("click", this.expand, this);
35920 this.stickBtn.hide();
35925 /** This region's collapsed element
35926 * @type Roo.Element */
35929 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35930 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35933 if(c.floatable !== false){
35934 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35935 this.collapsedEl.on("click", this.collapseClick, this);
35938 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35939 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35940 id: "message", unselectable: "on", style:{"float":"left"}});
35941 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35943 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35944 this.expandBtn.on("click", this.expand, this);
35948 if(this.collapseBtn){
35949 this.collapseBtn.setVisible(c.collapsible == true);
35952 this.cmargins = c.cmargins || this.cmargins ||
35953 (this.position == "west" || this.position == "east" ?
35954 {top: 0, left: 2, right:2, bottom: 0} :
35955 {top: 2, left: 0, right:0, bottom: 2});
35957 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35960 this.bottomTabs = c.tabPosition != "top";
35962 this.autoScroll = c.autoScroll || false;
35967 this.duration = c.duration || .30;
35968 this.slideDuration = c.slideDuration || .45;
35973 * Returns true if this region is currently visible.
35974 * @return {Boolean}
35976 isVisible : function(){
35977 return this.visible;
35981 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35982 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35984 //setCollapsedTitle : function(title){
35985 // title = title || " ";
35986 // if(this.collapsedTitleTextEl){
35987 // this.collapsedTitleTextEl.innerHTML = title;
35991 getBox : function(){
35993 // if(!this.collapsed){
35994 b = this.el.getBox(false, true);
35996 // b = this.collapsedEl.getBox(false, true);
36001 getMargins : function(){
36002 return this.margins;
36003 //return this.collapsed ? this.cmargins : this.margins;
36006 highlight : function(){
36007 this.el.addClass("x-layout-panel-dragover");
36010 unhighlight : function(){
36011 this.el.removeClass("x-layout-panel-dragover");
36014 updateBox : function(box)
36016 if (!this.bodyEl) {
36017 return; // not rendered yet..
36021 if(!this.collapsed){
36022 this.el.dom.style.left = box.x + "px";
36023 this.el.dom.style.top = box.y + "px";
36024 this.updateBody(box.width, box.height);
36026 this.collapsedEl.dom.style.left = box.x + "px";
36027 this.collapsedEl.dom.style.top = box.y + "px";
36028 this.collapsedEl.setSize(box.width, box.height);
36031 this.tabs.autoSizeTabs();
36035 updateBody : function(w, h)
36038 this.el.setWidth(w);
36039 w -= this.el.getBorderWidth("rl");
36040 if(this.config.adjustments){
36041 w += this.config.adjustments[0];
36044 if(h !== null && h > 0){
36045 this.el.setHeight(h);
36046 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36047 h -= this.el.getBorderWidth("tb");
36048 if(this.config.adjustments){
36049 h += this.config.adjustments[1];
36051 this.bodyEl.setHeight(h);
36053 h = this.tabs.syncHeight(h);
36056 if(this.panelSize){
36057 w = w !== null ? w : this.panelSize.width;
36058 h = h !== null ? h : this.panelSize.height;
36060 if(this.activePanel){
36061 var el = this.activePanel.getEl();
36062 w = w !== null ? w : el.getWidth();
36063 h = h !== null ? h : el.getHeight();
36064 this.panelSize = {width: w, height: h};
36065 this.activePanel.setSize(w, h);
36067 if(Roo.isIE && this.tabs){
36068 this.tabs.el.repaint();
36073 * Returns the container element for this region.
36074 * @return {Roo.Element}
36076 getEl : function(){
36081 * Hides this region.
36084 //if(!this.collapsed){
36085 this.el.dom.style.left = "-2000px";
36088 // this.collapsedEl.dom.style.left = "-2000px";
36089 // this.collapsedEl.hide();
36091 this.visible = false;
36092 this.fireEvent("visibilitychange", this, false);
36096 * Shows this region if it was previously hidden.
36099 //if(!this.collapsed){
36102 // this.collapsedEl.show();
36104 this.visible = true;
36105 this.fireEvent("visibilitychange", this, true);
36108 closeClicked : function(){
36109 if(this.activePanel){
36110 this.remove(this.activePanel);
36114 collapseClick : function(e){
36116 e.stopPropagation();
36119 e.stopPropagation();
36125 * Collapses this region.
36126 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36129 collapse : function(skipAnim, skipCheck = false){
36130 if(this.collapsed) {
36134 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36136 this.collapsed = true;
36138 this.split.el.hide();
36140 if(this.config.animate && skipAnim !== true){
36141 this.fireEvent("invalidated", this);
36142 this.animateCollapse();
36144 this.el.setLocation(-20000,-20000);
36146 this.collapsedEl.show();
36147 this.fireEvent("collapsed", this);
36148 this.fireEvent("invalidated", this);
36154 animateCollapse : function(){
36159 * Expands this region if it was previously collapsed.
36160 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36161 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36164 expand : function(e, skipAnim){
36166 e.stopPropagation();
36168 if(!this.collapsed || this.el.hasActiveFx()) {
36172 this.afterSlideIn();
36175 this.collapsed = false;
36176 if(this.config.animate && skipAnim !== true){
36177 this.animateExpand();
36181 this.split.el.show();
36183 this.collapsedEl.setLocation(-2000,-2000);
36184 this.collapsedEl.hide();
36185 this.fireEvent("invalidated", this);
36186 this.fireEvent("expanded", this);
36190 animateExpand : function(){
36194 initTabs : function()
36196 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36198 var ts = new Roo.bootstrap.panel.Tabs({
36199 el: this.bodyEl.dom,
36200 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36201 disableTooltips: this.config.disableTabTips,
36202 toolbar : this.config.toolbar
36205 if(this.config.hideTabs){
36206 ts.stripWrap.setDisplayed(false);
36209 ts.resizeTabs = this.config.resizeTabs === true;
36210 ts.minTabWidth = this.config.minTabWidth || 40;
36211 ts.maxTabWidth = this.config.maxTabWidth || 250;
36212 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36213 ts.monitorResize = false;
36214 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36215 ts.bodyEl.addClass('roo-layout-tabs-body');
36216 this.panels.each(this.initPanelAsTab, this);
36219 initPanelAsTab : function(panel){
36220 var ti = this.tabs.addTab(
36224 this.config.closeOnTab && panel.isClosable(),
36227 if(panel.tabTip !== undefined){
36228 ti.setTooltip(panel.tabTip);
36230 ti.on("activate", function(){
36231 this.setActivePanel(panel);
36234 if(this.config.closeOnTab){
36235 ti.on("beforeclose", function(t, e){
36237 this.remove(panel);
36241 panel.tabItem = ti;
36246 updatePanelTitle : function(panel, title)
36248 if(this.activePanel == panel){
36249 this.updateTitle(title);
36252 var ti = this.tabs.getTab(panel.getEl().id);
36254 if(panel.tabTip !== undefined){
36255 ti.setTooltip(panel.tabTip);
36260 updateTitle : function(title){
36261 if(this.titleTextEl && !this.config.title){
36262 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36266 setActivePanel : function(panel)
36268 panel = this.getPanel(panel);
36269 if(this.activePanel && this.activePanel != panel){
36270 if(this.activePanel.setActiveState(false) === false){
36274 this.activePanel = panel;
36275 panel.setActiveState(true);
36276 if(this.panelSize){
36277 panel.setSize(this.panelSize.width, this.panelSize.height);
36280 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36282 this.updateTitle(panel.getTitle());
36284 this.fireEvent("invalidated", this);
36286 this.fireEvent("panelactivated", this, panel);
36290 * Shows the specified panel.
36291 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36292 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36294 showPanel : function(panel)
36296 panel = this.getPanel(panel);
36299 var tab = this.tabs.getTab(panel.getEl().id);
36300 if(tab.isHidden()){
36301 this.tabs.unhideTab(tab.id);
36305 this.setActivePanel(panel);
36312 * Get the active panel for this region.
36313 * @return {Roo.ContentPanel} The active panel or null
36315 getActivePanel : function(){
36316 return this.activePanel;
36319 validateVisibility : function(){
36320 if(this.panels.getCount() < 1){
36321 this.updateTitle(" ");
36322 this.closeBtn.hide();
36325 if(!this.isVisible()){
36332 * Adds the passed ContentPanel(s) to this region.
36333 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36334 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36336 add : function(panel)
36338 if(arguments.length > 1){
36339 for(var i = 0, len = arguments.length; i < len; i++) {
36340 this.add(arguments[i]);
36345 // if we have not been rendered yet, then we can not really do much of this..
36346 if (!this.bodyEl) {
36347 this.unrendered_panels.push(panel);
36354 if(this.hasPanel(panel)){
36355 this.showPanel(panel);
36358 panel.setRegion(this);
36359 this.panels.add(panel);
36360 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36361 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36362 // and hide them... ???
36363 this.bodyEl.dom.appendChild(panel.getEl().dom);
36364 if(panel.background !== true){
36365 this.setActivePanel(panel);
36367 this.fireEvent("paneladded", this, panel);
36374 this.initPanelAsTab(panel);
36378 if(panel.background !== true){
36379 this.tabs.activate(panel.getEl().id);
36381 this.fireEvent("paneladded", this, panel);
36386 * Hides the tab for the specified panel.
36387 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36389 hidePanel : function(panel){
36390 if(this.tabs && (panel = this.getPanel(panel))){
36391 this.tabs.hideTab(panel.getEl().id);
36396 * Unhides the tab for a previously hidden panel.
36397 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36399 unhidePanel : function(panel){
36400 if(this.tabs && (panel = this.getPanel(panel))){
36401 this.tabs.unhideTab(panel.getEl().id);
36405 clearPanels : function(){
36406 while(this.panels.getCount() > 0){
36407 this.remove(this.panels.first());
36412 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36413 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36414 * @param {Boolean} preservePanel Overrides the config preservePanel option
36415 * @return {Roo.ContentPanel} The panel that was removed
36417 remove : function(panel, preservePanel)
36419 panel = this.getPanel(panel);
36424 this.fireEvent("beforeremove", this, panel, e);
36425 if(e.cancel === true){
36428 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36429 var panelId = panel.getId();
36430 this.panels.removeKey(panelId);
36432 document.body.appendChild(panel.getEl().dom);
36435 this.tabs.removeTab(panel.getEl().id);
36436 }else if (!preservePanel){
36437 this.bodyEl.dom.removeChild(panel.getEl().dom);
36439 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36440 var p = this.panels.first();
36441 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36442 tempEl.appendChild(p.getEl().dom);
36443 this.bodyEl.update("");
36444 this.bodyEl.dom.appendChild(p.getEl().dom);
36446 this.updateTitle(p.getTitle());
36448 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36449 this.setActivePanel(p);
36451 panel.setRegion(null);
36452 if(this.activePanel == panel){
36453 this.activePanel = null;
36455 if(this.config.autoDestroy !== false && preservePanel !== true){
36456 try{panel.destroy();}catch(e){}
36458 this.fireEvent("panelremoved", this, panel);
36463 * Returns the TabPanel component used by this region
36464 * @return {Roo.TabPanel}
36466 getTabs : function(){
36470 createTool : function(parentEl, className){
36471 var btn = Roo.DomHelper.append(parentEl, {
36473 cls: "x-layout-tools-button",
36476 cls: "roo-layout-tools-button-inner " + className,
36480 btn.addClassOnOver("roo-layout-tools-button-over");
36485 * Ext JS Library 1.1.1
36486 * Copyright(c) 2006-2007, Ext JS, LLC.
36488 * Originally Released Under LGPL - original licence link has changed is not relivant.
36491 * <script type="text/javascript">
36497 * @class Roo.SplitLayoutRegion
36498 * @extends Roo.LayoutRegion
36499 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36501 Roo.bootstrap.layout.Split = function(config){
36502 this.cursor = config.cursor;
36503 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36506 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36508 splitTip : "Drag to resize.",
36509 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36510 useSplitTips : false,
36512 applyConfig : function(config){
36513 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36516 onRender : function(ctr,pos) {
36518 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36519 if(!this.config.split){
36524 var splitEl = Roo.DomHelper.append(ctr.dom, {
36526 id: this.el.id + "-split",
36527 cls: "roo-layout-split roo-layout-split-"+this.position,
36530 /** The SplitBar for this region
36531 * @type Roo.SplitBar */
36532 // does not exist yet...
36533 Roo.log([this.position, this.orientation]);
36535 this.split = new Roo.bootstrap.SplitBar({
36536 dragElement : splitEl,
36537 resizingElement: this.el,
36538 orientation : this.orientation
36541 this.split.on("moved", this.onSplitMove, this);
36542 this.split.useShim = this.config.useShim === true;
36543 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36544 if(this.useSplitTips){
36545 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36547 //if(config.collapsible){
36548 // this.split.el.on("dblclick", this.collapse, this);
36551 if(typeof this.config.minSize != "undefined"){
36552 this.split.minSize = this.config.minSize;
36554 if(typeof this.config.maxSize != "undefined"){
36555 this.split.maxSize = this.config.maxSize;
36557 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36558 this.hideSplitter();
36563 getHMaxSize : function(){
36564 var cmax = this.config.maxSize || 10000;
36565 var center = this.mgr.getRegion("center");
36566 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36569 getVMaxSize : function(){
36570 var cmax = this.config.maxSize || 10000;
36571 var center = this.mgr.getRegion("center");
36572 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36575 onSplitMove : function(split, newSize){
36576 this.fireEvent("resized", this, newSize);
36580 * Returns the {@link Roo.SplitBar} for this region.
36581 * @return {Roo.SplitBar}
36583 getSplitBar : function(){
36588 this.hideSplitter();
36589 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36592 hideSplitter : function(){
36594 this.split.el.setLocation(-2000,-2000);
36595 this.split.el.hide();
36601 this.split.el.show();
36603 Roo.bootstrap.layout.Split.superclass.show.call(this);
36606 beforeSlide: function(){
36607 if(Roo.isGecko){// firefox overflow auto bug workaround
36608 this.bodyEl.clip();
36610 this.tabs.bodyEl.clip();
36612 if(this.activePanel){
36613 this.activePanel.getEl().clip();
36615 if(this.activePanel.beforeSlide){
36616 this.activePanel.beforeSlide();
36622 afterSlide : function(){
36623 if(Roo.isGecko){// firefox overflow auto bug workaround
36624 this.bodyEl.unclip();
36626 this.tabs.bodyEl.unclip();
36628 if(this.activePanel){
36629 this.activePanel.getEl().unclip();
36630 if(this.activePanel.afterSlide){
36631 this.activePanel.afterSlide();
36637 initAutoHide : function(){
36638 if(this.autoHide !== false){
36639 if(!this.autoHideHd){
36640 var st = new Roo.util.DelayedTask(this.slideIn, this);
36641 this.autoHideHd = {
36642 "mouseout": function(e){
36643 if(!e.within(this.el, true)){
36647 "mouseover" : function(e){
36653 this.el.on(this.autoHideHd);
36657 clearAutoHide : function(){
36658 if(this.autoHide !== false){
36659 this.el.un("mouseout", this.autoHideHd.mouseout);
36660 this.el.un("mouseover", this.autoHideHd.mouseover);
36664 clearMonitor : function(){
36665 Roo.get(document).un("click", this.slideInIf, this);
36668 // these names are backwards but not changed for compat
36669 slideOut : function(){
36670 if(this.isSlid || this.el.hasActiveFx()){
36673 this.isSlid = true;
36674 if(this.collapseBtn){
36675 this.collapseBtn.hide();
36677 this.closeBtnState = this.closeBtn.getStyle('display');
36678 this.closeBtn.hide();
36680 this.stickBtn.show();
36683 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36684 this.beforeSlide();
36685 this.el.setStyle("z-index", 10001);
36686 this.el.slideIn(this.getSlideAnchor(), {
36687 callback: function(){
36689 this.initAutoHide();
36690 Roo.get(document).on("click", this.slideInIf, this);
36691 this.fireEvent("slideshow", this);
36698 afterSlideIn : function(){
36699 this.clearAutoHide();
36700 this.isSlid = false;
36701 this.clearMonitor();
36702 this.el.setStyle("z-index", "");
36703 if(this.collapseBtn){
36704 this.collapseBtn.show();
36706 this.closeBtn.setStyle('display', this.closeBtnState);
36708 this.stickBtn.hide();
36710 this.fireEvent("slidehide", this);
36713 slideIn : function(cb){
36714 if(!this.isSlid || this.el.hasActiveFx()){
36718 this.isSlid = false;
36719 this.beforeSlide();
36720 this.el.slideOut(this.getSlideAnchor(), {
36721 callback: function(){
36722 this.el.setLeftTop(-10000, -10000);
36724 this.afterSlideIn();
36732 slideInIf : function(e){
36733 if(!e.within(this.el)){
36738 animateCollapse : function(){
36739 this.beforeSlide();
36740 this.el.setStyle("z-index", 20000);
36741 var anchor = this.getSlideAnchor();
36742 this.el.slideOut(anchor, {
36743 callback : function(){
36744 this.el.setStyle("z-index", "");
36745 this.collapsedEl.slideIn(anchor, {duration:.3});
36747 this.el.setLocation(-10000,-10000);
36749 this.fireEvent("collapsed", this);
36756 animateExpand : function(){
36757 this.beforeSlide();
36758 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36759 this.el.setStyle("z-index", 20000);
36760 this.collapsedEl.hide({
36763 this.el.slideIn(this.getSlideAnchor(), {
36764 callback : function(){
36765 this.el.setStyle("z-index", "");
36768 this.split.el.show();
36770 this.fireEvent("invalidated", this);
36771 this.fireEvent("expanded", this);
36799 getAnchor : function(){
36800 return this.anchors[this.position];
36803 getCollapseAnchor : function(){
36804 return this.canchors[this.position];
36807 getSlideAnchor : function(){
36808 return this.sanchors[this.position];
36811 getAlignAdj : function(){
36812 var cm = this.cmargins;
36813 switch(this.position){
36829 getExpandAdj : function(){
36830 var c = this.collapsedEl, cm = this.cmargins;
36831 switch(this.position){
36833 return [-(cm.right+c.getWidth()+cm.left), 0];
36836 return [cm.right+c.getWidth()+cm.left, 0];
36839 return [0, -(cm.top+cm.bottom+c.getHeight())];
36842 return [0, cm.top+cm.bottom+c.getHeight()];
36848 * Ext JS Library 1.1.1
36849 * Copyright(c) 2006-2007, Ext JS, LLC.
36851 * Originally Released Under LGPL - original licence link has changed is not relivant.
36854 * <script type="text/javascript">
36857 * These classes are private internal classes
36859 Roo.bootstrap.layout.Center = function(config){
36860 config.region = "center";
36861 Roo.bootstrap.layout.Region.call(this, config);
36862 this.visible = true;
36863 this.minWidth = config.minWidth || 20;
36864 this.minHeight = config.minHeight || 20;
36867 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36869 // center panel can't be hidden
36873 // center panel can't be hidden
36876 getMinWidth: function(){
36877 return this.minWidth;
36880 getMinHeight: function(){
36881 return this.minHeight;
36894 Roo.bootstrap.layout.North = function(config)
36896 config.region = 'north';
36897 config.cursor = 'n-resize';
36899 Roo.bootstrap.layout.Split.call(this, config);
36903 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36904 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36905 this.split.el.addClass("roo-layout-split-v");
36907 var size = config.initialSize || config.height;
36908 if(typeof size != "undefined"){
36909 this.el.setHeight(size);
36912 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36914 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36918 getBox : function(){
36919 if(this.collapsed){
36920 return this.collapsedEl.getBox();
36922 var box = this.el.getBox();
36924 box.height += this.split.el.getHeight();
36929 updateBox : function(box){
36930 if(this.split && !this.collapsed){
36931 box.height -= this.split.el.getHeight();
36932 this.split.el.setLeft(box.x);
36933 this.split.el.setTop(box.y+box.height);
36934 this.split.el.setWidth(box.width);
36936 if(this.collapsed){
36937 this.updateBody(box.width, null);
36939 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36947 Roo.bootstrap.layout.South = function(config){
36948 config.region = 'south';
36949 config.cursor = 's-resize';
36950 Roo.bootstrap.layout.Split.call(this, config);
36952 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36953 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36954 this.split.el.addClass("roo-layout-split-v");
36956 var size = config.initialSize || config.height;
36957 if(typeof size != "undefined"){
36958 this.el.setHeight(size);
36962 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36963 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36964 getBox : function(){
36965 if(this.collapsed){
36966 return this.collapsedEl.getBox();
36968 var box = this.el.getBox();
36970 var sh = this.split.el.getHeight();
36977 updateBox : function(box){
36978 if(this.split && !this.collapsed){
36979 var sh = this.split.el.getHeight();
36982 this.split.el.setLeft(box.x);
36983 this.split.el.setTop(box.y-sh);
36984 this.split.el.setWidth(box.width);
36986 if(this.collapsed){
36987 this.updateBody(box.width, null);
36989 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36993 Roo.bootstrap.layout.East = function(config){
36994 config.region = "east";
36995 config.cursor = "e-resize";
36996 Roo.bootstrap.layout.Split.call(this, config);
36998 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36999 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37000 this.split.el.addClass("roo-layout-split-h");
37002 var size = config.initialSize || config.width;
37003 if(typeof size != "undefined"){
37004 this.el.setWidth(size);
37007 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37008 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37009 getBox : function(){
37010 if(this.collapsed){
37011 return this.collapsedEl.getBox();
37013 var box = this.el.getBox();
37015 var sw = this.split.el.getWidth();
37022 updateBox : function(box){
37023 if(this.split && !this.collapsed){
37024 var sw = this.split.el.getWidth();
37026 this.split.el.setLeft(box.x);
37027 this.split.el.setTop(box.y);
37028 this.split.el.setHeight(box.height);
37031 if(this.collapsed){
37032 this.updateBody(null, box.height);
37034 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37038 Roo.bootstrap.layout.West = function(config){
37039 config.region = "west";
37040 config.cursor = "w-resize";
37042 Roo.bootstrap.layout.Split.call(this, config);
37044 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37045 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37046 this.split.el.addClass("roo-layout-split-h");
37050 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37051 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37053 onRender: function(ctr, pos)
37055 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37056 var size = this.config.initialSize || this.config.width;
37057 if(typeof size != "undefined"){
37058 this.el.setWidth(size);
37062 getBox : function(){
37063 if(this.collapsed){
37064 return this.collapsedEl.getBox();
37066 var box = this.el.getBox();
37068 box.width += this.split.el.getWidth();
37073 updateBox : function(box){
37074 if(this.split && !this.collapsed){
37075 var sw = this.split.el.getWidth();
37077 this.split.el.setLeft(box.x+box.width);
37078 this.split.el.setTop(box.y);
37079 this.split.el.setHeight(box.height);
37081 if(this.collapsed){
37082 this.updateBody(null, box.height);
37084 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37087 Roo.namespace("Roo.bootstrap.panel");/*
37089 * Ext JS Library 1.1.1
37090 * Copyright(c) 2006-2007, Ext JS, LLC.
37092 * Originally Released Under LGPL - original licence link has changed is not relivant.
37095 * <script type="text/javascript">
37098 * @class Roo.ContentPanel
37099 * @extends Roo.util.Observable
37100 * A basic ContentPanel element.
37101 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37102 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37103 * @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
37104 * @cfg {Boolean} closable True if the panel can be closed/removed
37105 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37106 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37107 * @cfg {Toolbar} toolbar A toolbar for this panel
37108 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37109 * @cfg {String} title The title for this panel
37110 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37111 * @cfg {String} url Calls {@link #setUrl} with this value
37112 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37113 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37114 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37115 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37116 * @cfg {Boolean} badges render the badges
37119 * Create a new ContentPanel.
37120 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37121 * @param {String/Object} config A string to set only the title or a config object
37122 * @param {String} content (optional) Set the HTML content for this panel
37123 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37125 Roo.bootstrap.panel.Content = function( config){
37127 this.tpl = config.tpl || false;
37129 var el = config.el;
37130 var content = config.content;
37132 if(config.autoCreate){ // xtype is available if this is called from factory
37135 this.el = Roo.get(el);
37136 if(!this.el && config && config.autoCreate){
37137 if(typeof config.autoCreate == "object"){
37138 if(!config.autoCreate.id){
37139 config.autoCreate.id = config.id||el;
37141 this.el = Roo.DomHelper.append(document.body,
37142 config.autoCreate, true);
37144 var elcfg = { tag: "div",
37145 cls: "roo-layout-inactive-content",
37149 elcfg.html = config.html;
37153 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37156 this.closable = false;
37157 this.loaded = false;
37158 this.active = false;
37161 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37163 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37165 this.wrapEl = this.el; //this.el.wrap();
37167 if (config.toolbar.items) {
37168 ti = config.toolbar.items ;
37169 delete config.toolbar.items ;
37173 this.toolbar.render(this.wrapEl, 'before');
37174 for(var i =0;i < ti.length;i++) {
37175 // Roo.log(['add child', items[i]]);
37176 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37178 this.toolbar.items = nitems;
37179 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37180 delete config.toolbar;
37184 // xtype created footer. - not sure if will work as we normally have to render first..
37185 if (this.footer && !this.footer.el && this.footer.xtype) {
37186 if (!this.wrapEl) {
37187 this.wrapEl = this.el.wrap();
37190 this.footer.container = this.wrapEl.createChild();
37192 this.footer = Roo.factory(this.footer, Roo);
37197 if(typeof config == "string"){
37198 this.title = config;
37200 Roo.apply(this, config);
37204 this.resizeEl = Roo.get(this.resizeEl, true);
37206 this.resizeEl = this.el;
37208 // handle view.xtype
37216 * Fires when this panel is activated.
37217 * @param {Roo.ContentPanel} this
37221 * @event deactivate
37222 * Fires when this panel is activated.
37223 * @param {Roo.ContentPanel} this
37225 "deactivate" : true,
37229 * Fires when this panel is resized if fitToFrame is true.
37230 * @param {Roo.ContentPanel} this
37231 * @param {Number} width The width after any component adjustments
37232 * @param {Number} height The height after any component adjustments
37238 * Fires when this tab is created
37239 * @param {Roo.ContentPanel} this
37250 if(this.autoScroll){
37251 this.resizeEl.setStyle("overflow", "auto");
37253 // fix randome scrolling
37254 //this.el.on('scroll', function() {
37255 // Roo.log('fix random scolling');
37256 // this.scrollTo('top',0);
37259 content = content || this.content;
37261 this.setContent(content);
37263 if(config && config.url){
37264 this.setUrl(this.url, this.params, this.loadOnce);
37269 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37271 if (this.view && typeof(this.view.xtype) != 'undefined') {
37272 this.view.el = this.el.appendChild(document.createElement("div"));
37273 this.view = Roo.factory(this.view);
37274 this.view.render && this.view.render(false, '');
37278 this.fireEvent('render', this);
37281 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37285 setRegion : function(region){
37286 this.region = region;
37287 this.setActiveClass(region && !this.background);
37291 setActiveClass: function(state)
37294 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37295 this.el.setStyle('position','relative');
37297 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37298 this.el.setStyle('position', 'absolute');
37303 * Returns the toolbar for this Panel if one was configured.
37304 * @return {Roo.Toolbar}
37306 getToolbar : function(){
37307 return this.toolbar;
37310 setActiveState : function(active)
37312 this.active = active;
37313 this.setActiveClass(active);
37315 if(this.fireEvent("deactivate", this) === false){
37320 this.fireEvent("activate", this);
37324 * Updates this panel's element
37325 * @param {String} content The new content
37326 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37328 setContent : function(content, loadScripts){
37329 this.el.update(content, loadScripts);
37332 ignoreResize : function(w, h){
37333 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37336 this.lastSize = {width: w, height: h};
37341 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37342 * @return {Roo.UpdateManager} The UpdateManager
37344 getUpdateManager : function(){
37345 return this.el.getUpdateManager();
37348 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37349 * @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:
37352 url: "your-url.php",
37353 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37354 callback: yourFunction,
37355 scope: yourObject, //(optional scope)
37358 text: "Loading...",
37363 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37364 * 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.
37365 * @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}
37366 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37367 * @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.
37368 * @return {Roo.ContentPanel} this
37371 var um = this.el.getUpdateManager();
37372 um.update.apply(um, arguments);
37378 * 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.
37379 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37380 * @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)
37381 * @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)
37382 * @return {Roo.UpdateManager} The UpdateManager
37384 setUrl : function(url, params, loadOnce){
37385 if(this.refreshDelegate){
37386 this.removeListener("activate", this.refreshDelegate);
37388 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37389 this.on("activate", this.refreshDelegate);
37390 return this.el.getUpdateManager();
37393 _handleRefresh : function(url, params, loadOnce){
37394 if(!loadOnce || !this.loaded){
37395 var updater = this.el.getUpdateManager();
37396 updater.update(url, params, this._setLoaded.createDelegate(this));
37400 _setLoaded : function(){
37401 this.loaded = true;
37405 * Returns this panel's id
37408 getId : function(){
37413 * Returns this panel's element - used by regiosn to add.
37414 * @return {Roo.Element}
37416 getEl : function(){
37417 return this.wrapEl || this.el;
37422 adjustForComponents : function(width, height)
37424 //Roo.log('adjustForComponents ');
37425 if(this.resizeEl != this.el){
37426 width -= this.el.getFrameWidth('lr');
37427 height -= this.el.getFrameWidth('tb');
37430 var te = this.toolbar.getEl();
37431 te.setWidth(width);
37432 height -= te.getHeight();
37435 var te = this.footer.getEl();
37436 te.setWidth(width);
37437 height -= te.getHeight();
37441 if(this.adjustments){
37442 width += this.adjustments[0];
37443 height += this.adjustments[1];
37445 return {"width": width, "height": height};
37448 setSize : function(width, height){
37449 if(this.fitToFrame && !this.ignoreResize(width, height)){
37450 if(this.fitContainer && this.resizeEl != this.el){
37451 this.el.setSize(width, height);
37453 var size = this.adjustForComponents(width, height);
37454 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37455 this.fireEvent('resize', this, size.width, size.height);
37460 * Returns this panel's title
37463 getTitle : function(){
37465 if (typeof(this.title) != 'object') {
37470 for (var k in this.title) {
37471 if (!this.title.hasOwnProperty(k)) {
37475 if (k.indexOf('-') >= 0) {
37476 var s = k.split('-');
37477 for (var i = 0; i<s.length; i++) {
37478 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37481 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37488 * Set this panel's title
37489 * @param {String} title
37491 setTitle : function(title){
37492 this.title = title;
37494 this.region.updatePanelTitle(this, title);
37499 * Returns true is this panel was configured to be closable
37500 * @return {Boolean}
37502 isClosable : function(){
37503 return this.closable;
37506 beforeSlide : function(){
37508 this.resizeEl.clip();
37511 afterSlide : function(){
37513 this.resizeEl.unclip();
37517 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37518 * Will fail silently if the {@link #setUrl} method has not been called.
37519 * This does not activate the panel, just updates its content.
37521 refresh : function(){
37522 if(this.refreshDelegate){
37523 this.loaded = false;
37524 this.refreshDelegate();
37529 * Destroys this panel
37531 destroy : function(){
37532 this.el.removeAllListeners();
37533 var tempEl = document.createElement("span");
37534 tempEl.appendChild(this.el.dom);
37535 tempEl.innerHTML = "";
37541 * form - if the content panel contains a form - this is a reference to it.
37542 * @type {Roo.form.Form}
37546 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37547 * This contains a reference to it.
37553 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37563 * @param {Object} cfg Xtype definition of item to add.
37567 getChildContainer: function () {
37568 return this.getEl();
37573 var ret = new Roo.factory(cfg);
37578 if (cfg.xtype.match(/^Form$/)) {
37581 //if (this.footer) {
37582 // el = this.footer.container.insertSibling(false, 'before');
37584 el = this.el.createChild();
37587 this.form = new Roo.form.Form(cfg);
37590 if ( this.form.allItems.length) {
37591 this.form.render(el.dom);
37595 // should only have one of theses..
37596 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37597 // views.. should not be just added - used named prop 'view''
37599 cfg.el = this.el.appendChild(document.createElement("div"));
37602 var ret = new Roo.factory(cfg);
37604 ret.render && ret.render(false, ''); // render blank..
37614 * @class Roo.bootstrap.panel.Grid
37615 * @extends Roo.bootstrap.panel.Content
37617 * Create a new GridPanel.
37618 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37619 * @param {Object} config A the config object
37625 Roo.bootstrap.panel.Grid = function(config)
37629 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37630 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37632 config.el = this.wrapper;
37633 //this.el = this.wrapper;
37635 if (config.container) {
37636 // ctor'ed from a Border/panel.grid
37639 this.wrapper.setStyle("overflow", "hidden");
37640 this.wrapper.addClass('roo-grid-container');
37645 if(config.toolbar){
37646 var tool_el = this.wrapper.createChild();
37647 this.toolbar = Roo.factory(config.toolbar);
37649 if (config.toolbar.items) {
37650 ti = config.toolbar.items ;
37651 delete config.toolbar.items ;
37655 this.toolbar.render(tool_el);
37656 for(var i =0;i < ti.length;i++) {
37657 // Roo.log(['add child', items[i]]);
37658 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37660 this.toolbar.items = nitems;
37662 delete config.toolbar;
37665 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37666 config.grid.scrollBody = true;;
37667 config.grid.monitorWindowResize = false; // turn off autosizing
37668 config.grid.autoHeight = false;
37669 config.grid.autoWidth = false;
37671 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37673 if (config.background) {
37674 // render grid on panel activation (if panel background)
37675 this.on('activate', function(gp) {
37676 if (!gp.grid.rendered) {
37677 gp.grid.render(this.wrapper);
37678 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37683 this.grid.render(this.wrapper);
37684 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37687 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37688 // ??? needed ??? config.el = this.wrapper;
37693 // xtype created footer. - not sure if will work as we normally have to render first..
37694 if (this.footer && !this.footer.el && this.footer.xtype) {
37696 var ctr = this.grid.getView().getFooterPanel(true);
37697 this.footer.dataSource = this.grid.dataSource;
37698 this.footer = Roo.factory(this.footer, Roo);
37699 this.footer.render(ctr);
37709 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37710 getId : function(){
37711 return this.grid.id;
37715 * Returns the grid for this panel
37716 * @return {Roo.bootstrap.Table}
37718 getGrid : function(){
37722 setSize : function(width, height){
37723 if(!this.ignoreResize(width, height)){
37724 var grid = this.grid;
37725 var size = this.adjustForComponents(width, height);
37726 var gridel = grid.getGridEl();
37727 gridel.setSize(size.width, size.height);
37729 var thd = grid.getGridEl().select('thead',true).first();
37730 var tbd = grid.getGridEl().select('tbody', true).first();
37732 tbd.setSize(width, height - thd.getHeight());
37741 beforeSlide : function(){
37742 this.grid.getView().scroller.clip();
37745 afterSlide : function(){
37746 this.grid.getView().scroller.unclip();
37749 destroy : function(){
37750 this.grid.destroy();
37752 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37757 * @class Roo.bootstrap.panel.Nest
37758 * @extends Roo.bootstrap.panel.Content
37760 * Create a new Panel, that can contain a layout.Border.
37763 * @param {Roo.BorderLayout} layout The layout for this panel
37764 * @param {String/Object} config A string to set only the title or a config object
37766 Roo.bootstrap.panel.Nest = function(config)
37768 // construct with only one argument..
37769 /* FIXME - implement nicer consturctors
37770 if (layout.layout) {
37772 layout = config.layout;
37773 delete config.layout;
37775 if (layout.xtype && !layout.getEl) {
37776 // then layout needs constructing..
37777 layout = Roo.factory(layout, Roo);
37781 config.el = config.layout.getEl();
37783 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37785 config.layout.monitorWindowResize = false; // turn off autosizing
37786 this.layout = config.layout;
37787 this.layout.getEl().addClass("roo-layout-nested-layout");
37794 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37796 setSize : function(width, height){
37797 if(!this.ignoreResize(width, height)){
37798 var size = this.adjustForComponents(width, height);
37799 var el = this.layout.getEl();
37800 if (size.height < 1) {
37801 el.setWidth(size.width);
37803 el.setSize(size.width, size.height);
37805 var touch = el.dom.offsetWidth;
37806 this.layout.layout();
37807 // ie requires a double layout on the first pass
37808 if(Roo.isIE && !this.initialized){
37809 this.initialized = true;
37810 this.layout.layout();
37815 // activate all subpanels if not currently active..
37817 setActiveState : function(active){
37818 this.active = active;
37819 this.setActiveClass(active);
37822 this.fireEvent("deactivate", this);
37826 this.fireEvent("activate", this);
37827 // not sure if this should happen before or after..
37828 if (!this.layout) {
37829 return; // should not happen..
37832 for (var r in this.layout.regions) {
37833 reg = this.layout.getRegion(r);
37834 if (reg.getActivePanel()) {
37835 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37836 reg.setActivePanel(reg.getActivePanel());
37839 if (!reg.panels.length) {
37842 reg.showPanel(reg.getPanel(0));
37851 * Returns the nested BorderLayout for this panel
37852 * @return {Roo.BorderLayout}
37854 getLayout : function(){
37855 return this.layout;
37859 * Adds a xtype elements to the layout of the nested panel
37863 xtype : 'ContentPanel',
37870 xtype : 'NestedLayoutPanel',
37876 items : [ ... list of content panels or nested layout panels.. ]
37880 * @param {Object} cfg Xtype definition of item to add.
37882 addxtype : function(cfg) {
37883 return this.layout.addxtype(cfg);
37888 * Ext JS Library 1.1.1
37889 * Copyright(c) 2006-2007, Ext JS, LLC.
37891 * Originally Released Under LGPL - original licence link has changed is not relivant.
37894 * <script type="text/javascript">
37897 * @class Roo.TabPanel
37898 * @extends Roo.util.Observable
37899 * A lightweight tab container.
37903 // basic tabs 1, built from existing content
37904 var tabs = new Roo.TabPanel("tabs1");
37905 tabs.addTab("script", "View Script");
37906 tabs.addTab("markup", "View Markup");
37907 tabs.activate("script");
37909 // more advanced tabs, built from javascript
37910 var jtabs = new Roo.TabPanel("jtabs");
37911 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37913 // set up the UpdateManager
37914 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37915 var updater = tab2.getUpdateManager();
37916 updater.setDefaultUrl("ajax1.htm");
37917 tab2.on('activate', updater.refresh, updater, true);
37919 // Use setUrl for Ajax loading
37920 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37921 tab3.setUrl("ajax2.htm", null, true);
37924 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37927 jtabs.activate("jtabs-1");
37930 * Create a new TabPanel.
37931 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37932 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37934 Roo.bootstrap.panel.Tabs = function(config){
37936 * The container element for this TabPanel.
37937 * @type Roo.Element
37939 this.el = Roo.get(config.el);
37942 if(typeof config == "boolean"){
37943 this.tabPosition = config ? "bottom" : "top";
37945 Roo.apply(this, config);
37949 if(this.tabPosition == "bottom"){
37950 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37951 this.el.addClass("roo-tabs-bottom");
37953 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37954 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37955 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
37956 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37958 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37960 if(this.tabPosition != "bottom"){
37961 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37962 * @type Roo.Element
37964 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37965 this.el.addClass("roo-tabs-top");
37969 this.bodyEl.setStyle("position", "relative");
37971 this.active = null;
37972 this.activateDelegate = this.activate.createDelegate(this);
37977 * Fires when the active tab changes
37978 * @param {Roo.TabPanel} this
37979 * @param {Roo.TabPanelItem} activePanel The new active tab
37983 * @event beforetabchange
37984 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37985 * @param {Roo.TabPanel} this
37986 * @param {Object} e Set cancel to true on this object to cancel the tab change
37987 * @param {Roo.TabPanelItem} tab The tab being changed to
37989 "beforetabchange" : true
37992 Roo.EventManager.onWindowResize(this.onResize, this);
37993 this.cpad = this.el.getPadding("lr");
37994 this.hiddenCount = 0;
37997 // toolbar on the tabbar support...
37998 if (this.toolbar) {
37999 alert("no toolbar support yet");
38000 this.toolbar = false;
38002 var tcfg = this.toolbar;
38003 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38004 this.toolbar = new Roo.Toolbar(tcfg);
38005 if (Roo.isSafari) {
38006 var tbl = tcfg.container.child('table', true);
38007 tbl.setAttribute('width', '100%');
38015 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38018 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38020 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38022 tabPosition : "top",
38024 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38026 currentTabWidth : 0,
38028 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38032 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38036 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38038 preferredTabWidth : 175,
38040 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38042 resizeTabs : false,
38044 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38046 monitorResize : true,
38048 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38053 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38054 * @param {String} id The id of the div to use <b>or create</b>
38055 * @param {String} text The text for the tab
38056 * @param {String} content (optional) Content to put in the TabPanelItem body
38057 * @param {Boolean} closable (optional) True to create a close icon on the tab
38058 * @return {Roo.TabPanelItem} The created TabPanelItem
38060 addTab : function(id, text, content, closable, tpl)
38062 var item = new Roo.bootstrap.panel.TabItem({
38066 closable : closable,
38069 this.addTabItem(item);
38071 item.setContent(content);
38077 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38078 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38079 * @return {Roo.TabPanelItem}
38081 getTab : function(id){
38082 return this.items[id];
38086 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38087 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38089 hideTab : function(id){
38090 var t = this.items[id];
38093 this.hiddenCount++;
38094 this.autoSizeTabs();
38099 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38100 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38102 unhideTab : function(id){
38103 var t = this.items[id];
38105 t.setHidden(false);
38106 this.hiddenCount--;
38107 this.autoSizeTabs();
38112 * Adds an existing {@link Roo.TabPanelItem}.
38113 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38115 addTabItem : function(item)
38117 this.items[item.id] = item;
38118 this.items.push(item);
38119 this.autoSizeTabs();
38120 // if(this.resizeTabs){
38121 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38122 // this.autoSizeTabs();
38124 // item.autoSize();
38129 * Removes a {@link Roo.TabPanelItem}.
38130 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38132 removeTab : function(id){
38133 var items = this.items;
38134 var tab = items[id];
38135 if(!tab) { return; }
38136 var index = items.indexOf(tab);
38137 if(this.active == tab && items.length > 1){
38138 var newTab = this.getNextAvailable(index);
38143 this.stripEl.dom.removeChild(tab.pnode.dom);
38144 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38145 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38147 items.splice(index, 1);
38148 delete this.items[tab.id];
38149 tab.fireEvent("close", tab);
38150 tab.purgeListeners();
38151 this.autoSizeTabs();
38154 getNextAvailable : function(start){
38155 var items = this.items;
38157 // look for a next tab that will slide over to
38158 // replace the one being removed
38159 while(index < items.length){
38160 var item = items[++index];
38161 if(item && !item.isHidden()){
38165 // if one isn't found select the previous tab (on the left)
38168 var item = items[--index];
38169 if(item && !item.isHidden()){
38177 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38178 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38180 disableTab : function(id){
38181 var tab = this.items[id];
38182 if(tab && this.active != tab){
38188 * Enables a {@link Roo.TabPanelItem} that is disabled.
38189 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38191 enableTab : function(id){
38192 var tab = this.items[id];
38197 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38198 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38199 * @return {Roo.TabPanelItem} The TabPanelItem.
38201 activate : function(id)
38203 var tab = this.items[id];
38207 if(tab == this.active || tab.disabled){
38211 this.fireEvent("beforetabchange", this, e, tab);
38212 if(e.cancel !== true && !tab.disabled){
38214 this.active.hide();
38216 this.active = this.items[id];
38217 this.active.show();
38218 this.fireEvent("tabchange", this, this.active);
38224 * Gets the active {@link Roo.TabPanelItem}.
38225 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38227 getActiveTab : function(){
38228 return this.active;
38232 * Updates the tab body element to fit the height of the container element
38233 * for overflow scrolling
38234 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38236 syncHeight : function(targetHeight){
38237 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38238 var bm = this.bodyEl.getMargins();
38239 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38240 this.bodyEl.setHeight(newHeight);
38244 onResize : function(){
38245 if(this.monitorResize){
38246 this.autoSizeTabs();
38251 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38253 beginUpdate : function(){
38254 this.updating = true;
38258 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38260 endUpdate : function(){
38261 this.updating = false;
38262 this.autoSizeTabs();
38266 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38268 autoSizeTabs : function()
38270 var count = this.items.length;
38271 var vcount = count - this.hiddenCount;
38274 this.stripEl.hide();
38276 this.stripEl.show();
38279 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38284 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38285 var availWidth = Math.floor(w / vcount);
38286 var b = this.stripBody;
38287 if(b.getWidth() > w){
38288 var tabs = this.items;
38289 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38290 if(availWidth < this.minTabWidth){
38291 /*if(!this.sleft){ // incomplete scrolling code
38292 this.createScrollButtons();
38295 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38298 if(this.currentTabWidth < this.preferredTabWidth){
38299 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38305 * Returns the number of tabs in this TabPanel.
38308 getCount : function(){
38309 return this.items.length;
38313 * Resizes all the tabs to the passed width
38314 * @param {Number} The new width
38316 setTabWidth : function(width){
38317 this.currentTabWidth = width;
38318 for(var i = 0, len = this.items.length; i < len; i++) {
38319 if(!this.items[i].isHidden()) {
38320 this.items[i].setWidth(width);
38326 * Destroys this TabPanel
38327 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38329 destroy : function(removeEl){
38330 Roo.EventManager.removeResizeListener(this.onResize, this);
38331 for(var i = 0, len = this.items.length; i < len; i++){
38332 this.items[i].purgeListeners();
38334 if(removeEl === true){
38335 this.el.update("");
38340 createStrip : function(container)
38342 var strip = document.createElement("nav");
38343 strip.className = Roo.bootstrap.version == 4 ?
38344 "navbar-light bg-light" :
38345 "navbar navbar-default"; //"x-tabs-wrap";
38346 container.appendChild(strip);
38350 createStripList : function(strip)
38352 // div wrapper for retard IE
38353 // returns the "tr" element.
38354 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38355 //'<div class="x-tabs-strip-wrap">'+
38356 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38357 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38358 return strip.firstChild; //.firstChild.firstChild.firstChild;
38360 createBody : function(container)
38362 var body = document.createElement("div");
38363 Roo.id(body, "tab-body");
38364 //Roo.fly(body).addClass("x-tabs-body");
38365 Roo.fly(body).addClass("tab-content");
38366 container.appendChild(body);
38369 createItemBody :function(bodyEl, id){
38370 var body = Roo.getDom(id);
38372 body = document.createElement("div");
38375 //Roo.fly(body).addClass("x-tabs-item-body");
38376 Roo.fly(body).addClass("tab-pane");
38377 bodyEl.insertBefore(body, bodyEl.firstChild);
38381 createStripElements : function(stripEl, text, closable, tpl)
38383 var td = document.createElement("li"); // was td..
38384 td.className = 'nav-item';
38386 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38389 stripEl.appendChild(td);
38391 td.className = "x-tabs-closable";
38392 if(!this.closeTpl){
38393 this.closeTpl = new Roo.Template(
38394 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38395 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38396 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38399 var el = this.closeTpl.overwrite(td, {"text": text});
38400 var close = el.getElementsByTagName("div")[0];
38401 var inner = el.getElementsByTagName("em")[0];
38402 return {"el": el, "close": close, "inner": inner};
38405 // not sure what this is..
38406 // if(!this.tabTpl){
38407 //this.tabTpl = new Roo.Template(
38408 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38409 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38411 // this.tabTpl = new Roo.Template(
38412 // '<a href="#">' +
38413 // '<span unselectable="on"' +
38414 // (this.disableTooltips ? '' : ' title="{text}"') +
38415 // ' >{text}</span></a>'
38421 var template = tpl || this.tabTpl || false;
38424 template = new Roo.Template(
38425 Roo.bootstrap.version == 4 ?
38427 '<a class="nav-link" href="#" unselectable="on"' +
38428 (this.disableTooltips ? '' : ' title="{text}"') +
38431 '<a class="nav-link" href="#">' +
38432 '<span unselectable="on"' +
38433 (this.disableTooltips ? '' : ' title="{text}"') +
38434 ' >{text}</span></a>'
38439 switch (typeof(template)) {
38443 template = new Roo.Template(template);
38449 var el = template.overwrite(td, {"text": text});
38451 var inner = el.getElementsByTagName("span")[0];
38453 return {"el": el, "inner": inner};
38461 * @class Roo.TabPanelItem
38462 * @extends Roo.util.Observable
38463 * Represents an individual item (tab plus body) in a TabPanel.
38464 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38465 * @param {String} id The id of this TabPanelItem
38466 * @param {String} text The text for the tab of this TabPanelItem
38467 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38469 Roo.bootstrap.panel.TabItem = function(config){
38471 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38472 * @type Roo.TabPanel
38474 this.tabPanel = config.panel;
38476 * The id for this TabPanelItem
38479 this.id = config.id;
38481 this.disabled = false;
38483 this.text = config.text;
38485 this.loaded = false;
38486 this.closable = config.closable;
38489 * The body element for this TabPanelItem.
38490 * @type Roo.Element
38492 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38493 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38494 this.bodyEl.setStyle("display", "block");
38495 this.bodyEl.setStyle("zoom", "1");
38496 //this.hideAction();
38498 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38500 this.el = Roo.get(els.el);
38501 this.inner = Roo.get(els.inner, true);
38502 this.textEl = Roo.bootstrap.version == 4 ?
38503 this.el : Roo.get(this.el.dom.firstChild, true);
38505 this.linode = Roo.get(els.el.parentNode, true);
38506 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38509 // this.el.on("mousedown", this.onTabMouseDown, this);
38510 this.el.on("click", this.onTabClick, this);
38512 if(config.closable){
38513 var c = Roo.get(els.close, true);
38514 c.dom.title = this.closeText;
38515 c.addClassOnOver("close-over");
38516 c.on("click", this.closeClick, this);
38522 * Fires when this tab becomes the active tab.
38523 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38524 * @param {Roo.TabPanelItem} this
38528 * @event beforeclose
38529 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38530 * @param {Roo.TabPanelItem} this
38531 * @param {Object} e Set cancel to true on this object to cancel the close.
38533 "beforeclose": true,
38536 * Fires when this tab is closed.
38537 * @param {Roo.TabPanelItem} this
38541 * @event deactivate
38542 * Fires when this tab is no longer the active tab.
38543 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38544 * @param {Roo.TabPanelItem} this
38546 "deactivate" : true
38548 this.hidden = false;
38550 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38553 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38555 purgeListeners : function(){
38556 Roo.util.Observable.prototype.purgeListeners.call(this);
38557 this.el.removeAllListeners();
38560 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38563 this.status_node.addClass("active");
38566 this.tabPanel.stripWrap.repaint();
38568 this.fireEvent("activate", this.tabPanel, this);
38572 * Returns true if this tab is the active tab.
38573 * @return {Boolean}
38575 isActive : function(){
38576 return this.tabPanel.getActiveTab() == this;
38580 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38583 this.status_node.removeClass("active");
38585 this.fireEvent("deactivate", this.tabPanel, this);
38588 hideAction : function(){
38589 this.bodyEl.hide();
38590 this.bodyEl.setStyle("position", "absolute");
38591 this.bodyEl.setLeft("-20000px");
38592 this.bodyEl.setTop("-20000px");
38595 showAction : function(){
38596 this.bodyEl.setStyle("position", "relative");
38597 this.bodyEl.setTop("");
38598 this.bodyEl.setLeft("");
38599 this.bodyEl.show();
38603 * Set the tooltip for the tab.
38604 * @param {String} tooltip The tab's tooltip
38606 setTooltip : function(text){
38607 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38608 this.textEl.dom.qtip = text;
38609 this.textEl.dom.removeAttribute('title');
38611 this.textEl.dom.title = text;
38615 onTabClick : function(e){
38616 e.preventDefault();
38617 this.tabPanel.activate(this.id);
38620 onTabMouseDown : function(e){
38621 e.preventDefault();
38622 this.tabPanel.activate(this.id);
38625 getWidth : function(){
38626 return this.inner.getWidth();
38629 setWidth : function(width){
38630 var iwidth = width - this.linode.getPadding("lr");
38631 this.inner.setWidth(iwidth);
38632 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38633 this.linode.setWidth(width);
38637 * Show or hide the tab
38638 * @param {Boolean} hidden True to hide or false to show.
38640 setHidden : function(hidden){
38641 this.hidden = hidden;
38642 this.linode.setStyle("display", hidden ? "none" : "");
38646 * Returns true if this tab is "hidden"
38647 * @return {Boolean}
38649 isHidden : function(){
38650 return this.hidden;
38654 * Returns the text for this tab
38657 getText : function(){
38661 autoSize : function(){
38662 //this.el.beginMeasure();
38663 this.textEl.setWidth(1);
38665 * #2804 [new] Tabs in Roojs
38666 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38668 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38669 //this.el.endMeasure();
38673 * Sets the text for the tab (Note: this also sets the tooltip text)
38674 * @param {String} text The tab's text and tooltip
38676 setText : function(text){
38678 this.textEl.update(text);
38679 this.setTooltip(text);
38680 //if(!this.tabPanel.resizeTabs){
38681 // this.autoSize();
38685 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38687 activate : function(){
38688 this.tabPanel.activate(this.id);
38692 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38694 disable : function(){
38695 if(this.tabPanel.active != this){
38696 this.disabled = true;
38697 this.status_node.addClass("disabled");
38702 * Enables this TabPanelItem if it was previously disabled.
38704 enable : function(){
38705 this.disabled = false;
38706 this.status_node.removeClass("disabled");
38710 * Sets the content for this TabPanelItem.
38711 * @param {String} content The content
38712 * @param {Boolean} loadScripts true to look for and load scripts
38714 setContent : function(content, loadScripts){
38715 this.bodyEl.update(content, loadScripts);
38719 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38720 * @return {Roo.UpdateManager} The UpdateManager
38722 getUpdateManager : function(){
38723 return this.bodyEl.getUpdateManager();
38727 * Set a URL to be used to load the content for this TabPanelItem.
38728 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38729 * @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)
38730 * @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)
38731 * @return {Roo.UpdateManager} The UpdateManager
38733 setUrl : function(url, params, loadOnce){
38734 if(this.refreshDelegate){
38735 this.un('activate', this.refreshDelegate);
38737 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38738 this.on("activate", this.refreshDelegate);
38739 return this.bodyEl.getUpdateManager();
38743 _handleRefresh : function(url, params, loadOnce){
38744 if(!loadOnce || !this.loaded){
38745 var updater = this.bodyEl.getUpdateManager();
38746 updater.update(url, params, this._setLoaded.createDelegate(this));
38751 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38752 * Will fail silently if the setUrl method has not been called.
38753 * This does not activate the panel, just updates its content.
38755 refresh : function(){
38756 if(this.refreshDelegate){
38757 this.loaded = false;
38758 this.refreshDelegate();
38763 _setLoaded : function(){
38764 this.loaded = true;
38768 closeClick : function(e){
38771 this.fireEvent("beforeclose", this, o);
38772 if(o.cancel !== true){
38773 this.tabPanel.removeTab(this.id);
38777 * The text displayed in the tooltip for the close icon.
38780 closeText : "Close this tab"
38783 * This script refer to:
38784 * Title: International Telephone Input
38785 * Author: Jack O'Connor
38786 * Code version: v12.1.12
38787 * Availability: https://github.com/jackocnr/intl-tel-input.git
38790 Roo.bootstrap.PhoneInputData = function() {
38793 "Afghanistan (افغانستان)",
38798 "Albania (Shqipëri)",
38803 "Algeria (الجزائر)",
38828 "Antigua and Barbuda",
38838 "Armenia (Հայաստան)",
38854 "Austria (Österreich)",
38859 "Azerbaijan (Azərbaycan)",
38869 "Bahrain (البحرين)",
38874 "Bangladesh (বাংলাদেশ)",
38884 "Belarus (Беларусь)",
38889 "Belgium (België)",
38919 "Bosnia and Herzegovina (Босна и Херцеговина)",
38934 "British Indian Ocean Territory",
38939 "British Virgin Islands",
38949 "Bulgaria (България)",
38959 "Burundi (Uburundi)",
38964 "Cambodia (កម្ពុជា)",
38969 "Cameroon (Cameroun)",
38978 ["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"]
38981 "Cape Verde (Kabu Verdi)",
38986 "Caribbean Netherlands",
38997 "Central African Republic (République centrafricaine)",
39017 "Christmas Island",
39023 "Cocos (Keeling) Islands",
39034 "Comoros (جزر القمر)",
39039 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39044 "Congo (Republic) (Congo-Brazzaville)",
39064 "Croatia (Hrvatska)",
39085 "Czech Republic (Česká republika)",
39090 "Denmark (Danmark)",
39105 "Dominican Republic (República Dominicana)",
39109 ["809", "829", "849"]
39127 "Equatorial Guinea (Guinea Ecuatorial)",
39147 "Falkland Islands (Islas Malvinas)",
39152 "Faroe Islands (Føroyar)",
39173 "French Guiana (Guyane française)",
39178 "French Polynesia (Polynésie française)",
39193 "Georgia (საქართველო)",
39198 "Germany (Deutschland)",
39218 "Greenland (Kalaallit Nunaat)",
39255 "Guinea-Bissau (Guiné Bissau)",
39280 "Hungary (Magyarország)",
39285 "Iceland (Ísland)",
39305 "Iraq (العراق)",
39321 "Israel (ישראל)",
39348 "Jordan (الأردن)",
39353 "Kazakhstan (Казахстан)",
39374 "Kuwait (الكويت)",
39379 "Kyrgyzstan (Кыргызстан)",
39389 "Latvia (Latvija)",
39394 "Lebanon (لبنان)",
39409 "Libya (ليبيا)",
39419 "Lithuania (Lietuva)",
39434 "Macedonia (FYROM) (Македонија)",
39439 "Madagascar (Madagasikara)",
39469 "Marshall Islands",
39479 "Mauritania (موريتانيا)",
39484 "Mauritius (Moris)",
39505 "Moldova (Republica Moldova)",
39515 "Mongolia (Монгол)",
39520 "Montenegro (Crna Gora)",
39530 "Morocco (المغرب)",
39536 "Mozambique (Moçambique)",
39541 "Myanmar (Burma) (မြန်မာ)",
39546 "Namibia (Namibië)",
39561 "Netherlands (Nederland)",
39566 "New Caledonia (Nouvelle-Calédonie)",
39601 "North Korea (조선 민주주의 인민 공화국)",
39606 "Northern Mariana Islands",
39622 "Pakistan (پاکستان)",
39632 "Palestine (فلسطين)",
39642 "Papua New Guinea",
39684 "Réunion (La Réunion)",
39690 "Romania (România)",
39706 "Saint Barthélemy",
39717 "Saint Kitts and Nevis",
39727 "Saint Martin (Saint-Martin (partie française))",
39733 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39738 "Saint Vincent and the Grenadines",
39753 "São Tomé and Príncipe (São Tomé e Príncipe)",
39758 "Saudi Arabia (المملكة العربية السعودية)",
39763 "Senegal (Sénégal)",
39793 "Slovakia (Slovensko)",
39798 "Slovenia (Slovenija)",
39808 "Somalia (Soomaaliya)",
39818 "South Korea (대한민국)",
39823 "South Sudan (جنوب السودان)",
39833 "Sri Lanka (ශ්රී ලංකාව)",
39838 "Sudan (السودان)",
39848 "Svalbard and Jan Mayen",
39859 "Sweden (Sverige)",
39864 "Switzerland (Schweiz)",
39869 "Syria (سوريا)",
39914 "Trinidad and Tobago",
39919 "Tunisia (تونس)",
39924 "Turkey (Türkiye)",
39934 "Turks and Caicos Islands",
39944 "U.S. Virgin Islands",
39954 "Ukraine (Україна)",
39959 "United Arab Emirates (الإمارات العربية المتحدة)",
39981 "Uzbekistan (Oʻzbekiston)",
39991 "Vatican City (Città del Vaticano)",
40002 "Vietnam (Việt Nam)",
40007 "Wallis and Futuna (Wallis-et-Futuna)",
40012 "Western Sahara (الصحراء الغربية)",
40018 "Yemen (اليمن)",
40042 * This script refer to:
40043 * Title: International Telephone Input
40044 * Author: Jack O'Connor
40045 * Code version: v12.1.12
40046 * Availability: https://github.com/jackocnr/intl-tel-input.git
40050 * @class Roo.bootstrap.PhoneInput
40051 * @extends Roo.bootstrap.TriggerField
40052 * An input with International dial-code selection
40054 * @cfg {String} defaultDialCode default '+852'
40055 * @cfg {Array} preferedCountries default []
40058 * Create a new PhoneInput.
40059 * @param {Object} config Configuration options
40062 Roo.bootstrap.PhoneInput = function(config) {
40063 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40066 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40068 listWidth: undefined,
40070 selectedClass: 'active',
40072 invalidClass : "has-warning",
40074 validClass: 'has-success',
40076 allowed: '0123456789',
40081 * @cfg {String} defaultDialCode The default dial code when initializing the input
40083 defaultDialCode: '+852',
40086 * @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
40088 preferedCountries: false,
40090 getAutoCreate : function()
40092 var data = Roo.bootstrap.PhoneInputData();
40093 var align = this.labelAlign || this.parentLabelAlign();
40096 this.allCountries = [];
40097 this.dialCodeMapping = [];
40099 for (var i = 0; i < data.length; i++) {
40101 this.allCountries[i] = {
40105 priority: c[3] || 0,
40106 areaCodes: c[4] || null
40108 this.dialCodeMapping[c[2]] = {
40111 priority: c[3] || 0,
40112 areaCodes: c[4] || null
40124 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40125 maxlength: this.max_length,
40126 cls : 'form-control tel-input',
40127 autocomplete: 'new-password'
40130 var hiddenInput = {
40133 cls: 'hidden-tel-input'
40137 hiddenInput.name = this.name;
40140 if (this.disabled) {
40141 input.disabled = true;
40144 var flag_container = {
40161 cls: this.hasFeedback ? 'has-feedback' : '',
40167 cls: 'dial-code-holder',
40174 cls: 'roo-select2-container input-group',
40181 if (this.fieldLabel.length) {
40184 tooltip: 'This field is required'
40190 cls: 'control-label',
40196 html: this.fieldLabel
40199 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40205 if(this.indicatorpos == 'right') {
40206 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40213 if(align == 'left') {
40221 if(this.labelWidth > 12){
40222 label.style = "width: " + this.labelWidth + 'px';
40224 if(this.labelWidth < 13 && this.labelmd == 0){
40225 this.labelmd = this.labelWidth;
40227 if(this.labellg > 0){
40228 label.cls += ' col-lg-' + this.labellg;
40229 input.cls += ' col-lg-' + (12 - this.labellg);
40231 if(this.labelmd > 0){
40232 label.cls += ' col-md-' + this.labelmd;
40233 container.cls += ' col-md-' + (12 - this.labelmd);
40235 if(this.labelsm > 0){
40236 label.cls += ' col-sm-' + this.labelsm;
40237 container.cls += ' col-sm-' + (12 - this.labelsm);
40239 if(this.labelxs > 0){
40240 label.cls += ' col-xs-' + this.labelxs;
40241 container.cls += ' col-xs-' + (12 - this.labelxs);
40251 var settings = this;
40253 ['xs','sm','md','lg'].map(function(size){
40254 if (settings[size]) {
40255 cfg.cls += ' col-' + size + '-' + settings[size];
40259 this.store = new Roo.data.Store({
40260 proxy : new Roo.data.MemoryProxy({}),
40261 reader : new Roo.data.JsonReader({
40272 'name' : 'dialCode',
40276 'name' : 'priority',
40280 'name' : 'areaCodes',
40287 if(!this.preferedCountries) {
40288 this.preferedCountries = [
40295 var p = this.preferedCountries.reverse();
40298 for (var i = 0; i < p.length; i++) {
40299 for (var j = 0; j < this.allCountries.length; j++) {
40300 if(this.allCountries[j].iso2 == p[i]) {
40301 var t = this.allCountries[j];
40302 this.allCountries.splice(j,1);
40303 this.allCountries.unshift(t);
40309 this.store.proxy.data = {
40311 data: this.allCountries
40317 initEvents : function()
40320 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40322 this.indicator = this.indicatorEl();
40323 this.flag = this.flagEl();
40324 this.dialCodeHolder = this.dialCodeHolderEl();
40326 this.trigger = this.el.select('div.flag-box',true).first();
40327 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40332 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40333 _this.list.setWidth(lw);
40336 this.list.on('mouseover', this.onViewOver, this);
40337 this.list.on('mousemove', this.onViewMove, this);
40338 this.inputEl().on("keyup", this.onKeyUp, this);
40339 this.inputEl().on("keypress", this.onKeyPress, this);
40341 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40343 this.view = new Roo.View(this.list, this.tpl, {
40344 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40347 this.view.on('click', this.onViewClick, this);
40348 this.setValue(this.defaultDialCode);
40351 onTriggerClick : function(e)
40353 Roo.log('trigger click');
40358 if(this.isExpanded()){
40360 this.hasFocus = false;
40362 this.store.load({});
40363 this.hasFocus = true;
40368 isExpanded : function()
40370 return this.list.isVisible();
40373 collapse : function()
40375 if(!this.isExpanded()){
40379 Roo.get(document).un('mousedown', this.collapseIf, this);
40380 Roo.get(document).un('mousewheel', this.collapseIf, this);
40381 this.fireEvent('collapse', this);
40385 expand : function()
40389 if(this.isExpanded() || !this.hasFocus){
40393 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40394 this.list.setWidth(lw);
40397 this.restrictHeight();
40399 Roo.get(document).on('mousedown', this.collapseIf, this);
40400 Roo.get(document).on('mousewheel', this.collapseIf, this);
40402 this.fireEvent('expand', this);
40405 restrictHeight : function()
40407 this.list.alignTo(this.inputEl(), this.listAlign);
40408 this.list.alignTo(this.inputEl(), this.listAlign);
40411 onViewOver : function(e, t)
40413 if(this.inKeyMode){
40416 var item = this.view.findItemFromChild(t);
40419 var index = this.view.indexOf(item);
40420 this.select(index, false);
40425 onViewClick : function(view, doFocus, el, e)
40427 var index = this.view.getSelectedIndexes()[0];
40429 var r = this.store.getAt(index);
40432 this.onSelect(r, index);
40434 if(doFocus !== false && !this.blockFocus){
40435 this.inputEl().focus();
40439 onViewMove : function(e, t)
40441 this.inKeyMode = false;
40444 select : function(index, scrollIntoView)
40446 this.selectedIndex = index;
40447 this.view.select(index);
40448 if(scrollIntoView !== false){
40449 var el = this.view.getNode(index);
40451 this.list.scrollChildIntoView(el, false);
40456 createList : function()
40458 this.list = Roo.get(document.body).createChild({
40460 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40461 style: 'display:none'
40464 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40467 collapseIf : function(e)
40469 var in_combo = e.within(this.el);
40470 var in_list = e.within(this.list);
40471 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40473 if (in_combo || in_list || is_list) {
40479 onSelect : function(record, index)
40481 if(this.fireEvent('beforeselect', this, record, index) !== false){
40483 this.setFlagClass(record.data.iso2);
40484 this.setDialCode(record.data.dialCode);
40485 this.hasFocus = false;
40487 this.fireEvent('select', this, record, index);
40491 flagEl : function()
40493 var flag = this.el.select('div.flag',true).first();
40500 dialCodeHolderEl : function()
40502 var d = this.el.select('input.dial-code-holder',true).first();
40509 setDialCode : function(v)
40511 this.dialCodeHolder.dom.value = '+'+v;
40514 setFlagClass : function(n)
40516 this.flag.dom.className = 'flag '+n;
40519 getValue : function()
40521 var v = this.inputEl().getValue();
40522 if(this.dialCodeHolder) {
40523 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40528 setValue : function(v)
40530 var d = this.getDialCode(v);
40532 //invalid dial code
40533 if(v.length == 0 || !d || d.length == 0) {
40535 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40536 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40542 this.setFlagClass(this.dialCodeMapping[d].iso2);
40543 this.setDialCode(d);
40544 this.inputEl().dom.value = v.replace('+'+d,'');
40545 this.hiddenEl().dom.value = this.getValue();
40550 getDialCode : function(v)
40554 if (v.length == 0) {
40555 return this.dialCodeHolder.dom.value;
40559 if (v.charAt(0) != "+") {
40562 var numericChars = "";
40563 for (var i = 1; i < v.length; i++) {
40564 var c = v.charAt(i);
40567 if (this.dialCodeMapping[numericChars]) {
40568 dialCode = v.substr(1, i);
40570 if (numericChars.length == 4) {
40580 this.setValue(this.defaultDialCode);
40584 hiddenEl : function()
40586 return this.el.select('input.hidden-tel-input',true).first();
40589 // after setting val
40590 onKeyUp : function(e){
40591 this.setValue(this.getValue());
40594 onKeyPress : function(e){
40595 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40602 * @class Roo.bootstrap.MoneyField
40603 * @extends Roo.bootstrap.ComboBox
40604 * Bootstrap MoneyField class
40607 * Create a new MoneyField.
40608 * @param {Object} config Configuration options
40611 Roo.bootstrap.MoneyField = function(config) {
40613 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40617 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40620 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40622 allowDecimals : true,
40624 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40626 decimalSeparator : ".",
40628 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40630 decimalPrecision : 0,
40632 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40634 allowNegative : true,
40636 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40640 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40642 minValue : Number.NEGATIVE_INFINITY,
40644 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40646 maxValue : Number.MAX_VALUE,
40648 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40650 minText : "The minimum value for this field is {0}",
40652 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40654 maxText : "The maximum value for this field is {0}",
40656 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40657 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40659 nanText : "{0} is not a valid number",
40661 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40665 * @cfg {String} defaults currency of the MoneyField
40666 * value should be in lkey
40668 defaultCurrency : false,
40670 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40672 thousandsDelimiter : false,
40674 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40685 getAutoCreate : function()
40687 var align = this.labelAlign || this.parentLabelAlign();
40699 cls : 'form-control roo-money-amount-input',
40700 autocomplete: 'new-password'
40703 var hiddenInput = {
40707 cls: 'hidden-number-input'
40710 if(this.max_length) {
40711 input.maxlength = this.max_length;
40715 hiddenInput.name = this.name;
40718 if (this.disabled) {
40719 input.disabled = true;
40722 var clg = 12 - this.inputlg;
40723 var cmd = 12 - this.inputmd;
40724 var csm = 12 - this.inputsm;
40725 var cxs = 12 - this.inputxs;
40729 cls : 'row roo-money-field',
40733 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40737 cls: 'roo-select2-container input-group',
40741 cls : 'form-control roo-money-currency-input',
40742 autocomplete: 'new-password',
40744 name : this.currencyName
40748 cls : 'input-group-addon',
40762 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40766 cls: this.hasFeedback ? 'has-feedback' : '',
40777 if (this.fieldLabel.length) {
40780 tooltip: 'This field is required'
40786 cls: 'control-label',
40792 html: this.fieldLabel
40795 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40801 if(this.indicatorpos == 'right') {
40802 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40809 if(align == 'left') {
40817 if(this.labelWidth > 12){
40818 label.style = "width: " + this.labelWidth + 'px';
40820 if(this.labelWidth < 13 && this.labelmd == 0){
40821 this.labelmd = this.labelWidth;
40823 if(this.labellg > 0){
40824 label.cls += ' col-lg-' + this.labellg;
40825 input.cls += ' col-lg-' + (12 - this.labellg);
40827 if(this.labelmd > 0){
40828 label.cls += ' col-md-' + this.labelmd;
40829 container.cls += ' col-md-' + (12 - this.labelmd);
40831 if(this.labelsm > 0){
40832 label.cls += ' col-sm-' + this.labelsm;
40833 container.cls += ' col-sm-' + (12 - this.labelsm);
40835 if(this.labelxs > 0){
40836 label.cls += ' col-xs-' + this.labelxs;
40837 container.cls += ' col-xs-' + (12 - this.labelxs);
40848 var settings = this;
40850 ['xs','sm','md','lg'].map(function(size){
40851 if (settings[size]) {
40852 cfg.cls += ' col-' + size + '-' + settings[size];
40859 initEvents : function()
40861 this.indicator = this.indicatorEl();
40863 this.initCurrencyEvent();
40865 this.initNumberEvent();
40868 initCurrencyEvent : function()
40871 throw "can not find store for combo";
40874 this.store = Roo.factory(this.store, Roo.data);
40875 this.store.parent = this;
40879 this.triggerEl = this.el.select('.input-group-addon', true).first();
40881 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40886 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40887 _this.list.setWidth(lw);
40890 this.list.on('mouseover', this.onViewOver, this);
40891 this.list.on('mousemove', this.onViewMove, this);
40892 this.list.on('scroll', this.onViewScroll, this);
40895 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40898 this.view = new Roo.View(this.list, this.tpl, {
40899 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40902 this.view.on('click', this.onViewClick, this);
40904 this.store.on('beforeload', this.onBeforeLoad, this);
40905 this.store.on('load', this.onLoad, this);
40906 this.store.on('loadexception', this.onLoadException, this);
40908 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40909 "up" : function(e){
40910 this.inKeyMode = true;
40914 "down" : function(e){
40915 if(!this.isExpanded()){
40916 this.onTriggerClick();
40918 this.inKeyMode = true;
40923 "enter" : function(e){
40926 if(this.fireEvent("specialkey", this, e)){
40927 this.onViewClick(false);
40933 "esc" : function(e){
40937 "tab" : function(e){
40940 if(this.fireEvent("specialkey", this, e)){
40941 this.onViewClick(false);
40949 doRelay : function(foo, bar, hname){
40950 if(hname == 'down' || this.scope.isExpanded()){
40951 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40959 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40963 initNumberEvent : function(e)
40965 this.inputEl().on("keydown" , this.fireKey, this);
40966 this.inputEl().on("focus", this.onFocus, this);
40967 this.inputEl().on("blur", this.onBlur, this);
40969 this.inputEl().relayEvent('keyup', this);
40971 if(this.indicator){
40972 this.indicator.addClass('invisible');
40975 this.originalValue = this.getValue();
40977 if(this.validationEvent == 'keyup'){
40978 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40979 this.inputEl().on('keyup', this.filterValidation, this);
40981 else if(this.validationEvent !== false){
40982 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40985 if(this.selectOnFocus){
40986 this.on("focus", this.preFocus, this);
40989 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40990 this.inputEl().on("keypress", this.filterKeys, this);
40992 this.inputEl().relayEvent('keypress', this);
40995 var allowed = "0123456789";
40997 if(this.allowDecimals){
40998 allowed += this.decimalSeparator;
41001 if(this.allowNegative){
41005 if(this.thousandsDelimiter) {
41009 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41011 var keyPress = function(e){
41013 var k = e.getKey();
41015 var c = e.getCharCode();
41018 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41019 allowed.indexOf(String.fromCharCode(c)) === -1
41025 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41029 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41034 this.inputEl().on("keypress", keyPress, this);
41038 onTriggerClick : function(e)
41045 this.loadNext = false;
41047 if(this.isExpanded()){
41052 this.hasFocus = true;
41054 if(this.triggerAction == 'all') {
41055 this.doQuery(this.allQuery, true);
41059 this.doQuery(this.getRawValue());
41062 getCurrency : function()
41064 var v = this.currencyEl().getValue();
41069 restrictHeight : function()
41071 this.list.alignTo(this.currencyEl(), this.listAlign);
41072 this.list.alignTo(this.currencyEl(), this.listAlign);
41075 onViewClick : function(view, doFocus, el, e)
41077 var index = this.view.getSelectedIndexes()[0];
41079 var r = this.store.getAt(index);
41082 this.onSelect(r, index);
41086 onSelect : function(record, index){
41088 if(this.fireEvent('beforeselect', this, record, index) !== false){
41090 this.setFromCurrencyData(index > -1 ? record.data : false);
41094 this.fireEvent('select', this, record, index);
41098 setFromCurrencyData : function(o)
41102 this.lastCurrency = o;
41104 if (this.currencyField) {
41105 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41107 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41110 this.lastSelectionText = currency;
41112 //setting default currency
41113 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41114 this.setCurrency(this.defaultCurrency);
41118 this.setCurrency(currency);
41121 setFromData : function(o)
41125 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41127 this.setFromCurrencyData(c);
41132 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41134 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41137 this.setValue(value);
41141 setCurrency : function(v)
41143 this.currencyValue = v;
41146 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41151 setValue : function(v)
41153 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41159 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41161 this.inputEl().dom.value = (v == '') ? '' :
41162 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41164 if(!this.allowZero && v === '0') {
41165 this.hiddenEl().dom.value = '';
41166 this.inputEl().dom.value = '';
41173 getRawValue : function()
41175 var v = this.inputEl().getValue();
41180 getValue : function()
41182 return this.fixPrecision(this.parseValue(this.getRawValue()));
41185 parseValue : function(value)
41187 if(this.thousandsDelimiter) {
41189 r = new RegExp(",", "g");
41190 value = value.replace(r, "");
41193 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41194 return isNaN(value) ? '' : value;
41198 fixPrecision : function(value)
41200 if(this.thousandsDelimiter) {
41202 r = new RegExp(",", "g");
41203 value = value.replace(r, "");
41206 var nan = isNaN(value);
41208 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41209 return nan ? '' : value;
41211 return parseFloat(value).toFixed(this.decimalPrecision);
41214 decimalPrecisionFcn : function(v)
41216 return Math.floor(v);
41219 validateValue : function(value)
41221 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41225 var num = this.parseValue(value);
41228 this.markInvalid(String.format(this.nanText, value));
41232 if(num < this.minValue){
41233 this.markInvalid(String.format(this.minText, this.minValue));
41237 if(num > this.maxValue){
41238 this.markInvalid(String.format(this.maxText, this.maxValue));
41245 validate : function()
41247 if(this.disabled || this.allowBlank){
41252 var currency = this.getCurrency();
41254 if(this.validateValue(this.getRawValue()) && currency.length){
41259 this.markInvalid();
41263 getName: function()
41268 beforeBlur : function()
41274 var v = this.parseValue(this.getRawValue());
41281 onBlur : function()
41285 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41286 //this.el.removeClass(this.focusClass);
41289 this.hasFocus = false;
41291 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41295 var v = this.getValue();
41297 if(String(v) !== String(this.startValue)){
41298 this.fireEvent('change', this, v, this.startValue);
41301 this.fireEvent("blur", this);
41304 inputEl : function()
41306 return this.el.select('.roo-money-amount-input', true).first();
41309 currencyEl : function()
41311 return this.el.select('.roo-money-currency-input', true).first();
41314 hiddenEl : function()
41316 return this.el.select('input.hidden-number-input',true).first();